From 395c216ad03732166c09b42138dc3c6ff87300e7 Mon Sep 17 00:00:00 2001 From: shashi165 <33355509+shashi165@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:56:16 -0500 Subject: [PATCH] Feat/merge mowali branch (#1) * Issue934-FixSetEnvVarRCAsBooleanInsteadOfString (#81) * Issue934-FixSetEnvVarRCAsBooleanInsteadOfString * Issue934-JestUnitTestChangeUpdate * WIP * mockConfig done * Issue934-AddParseStringInObjectDependencyAndUpdateDeps * Issue934-UpdatePackageVersionTo8dot4dot1-snapshotAndUpdateDependencies * bugfix/1066 Remove Put Accept Header (#86) - Added noAccept parameter - Upgraded dependencies * More unit tests and some code cleanup (#87) * Tests converted to Jest * Added rules engine jsonpath dynamic fact * Updated rules engine API. Added jsonpath package to dependencies. Added rules engine tests. Added Jest config. Added example rules.json. * Updated hapi/subtext to patch vulnerability * Updated example rules and corresponding tests to reflect real form of payer and payee * Added switch endpoint to config to obtain payer and payee information for rules engine. Stubbed validateQuoteRequest method in relevant tests. Running rules engine in validateQuoteRequest (but not doing anything with the results yet). * Tests converted to Jest * Replaced coverage-check script. Added coverage threshold to jest config. Removed Istanbul config. * Uninstalled and reinstalled jest to fix vulnerability * Added junit + config. Added test:junit npm script. Modified circle config to call junit script. Added test results directory to gitignore. * Modified example rules and corresponding tests to better reflect actual payer and payee facts * Updated redirect address to redirect fsp. Made the linter happy. Added rule execution and event handling. Removed empty quote validation, replaced with rules engine execution. Removed redundant setImmediate. New test for INVALID_QUOTE_REQUEST event. Expanded INVALID_QUOTE_REQUEST unit tests. * Manual merge from upstream * Integrated properly the new `model/rules.js` into `model/quotes.js` and updated the `quotes.tests.js` accordingly. * Simplified block of code that was unnecessarily using `map`. * Forwarding event-handler-modified quote request and headers instead of originals * Fixed tests by poorly mocking handleRuleEvents on the quotes model * Cleaned a little bit the result of `handleRuleEvents`; Updated unit tests in order to pass according to latest code changes. * Deduplicated the functionality of request sending * Removed `setImmediate` from all places that it was used. * Use `CreateInternalServerFSPIOPError` instead of `CreateFSPIOPError` * fixed the name of rules.json * rename file rules.example.json * Refactored existing unit tests in order to make them cleaner and avoid duplication; Added more unit tests for `handleQuoteRequest` to cover all possible paths. * Refactored `handleQuoteRequest` to make it more readable and avoid duplication; Cleaned some minor parts of the whole `quotes.js` file. * Resolved issue with merge * Added unit tests for `quotesModel.handleRuleEvents` * Minor update to behaviour and corresponding test update. Minor test change. * Lint fix * Added unit tests for `quotesModel.executeRules` * Added more unit tests to `quotesModel.executeRules` to cover rejected promises of `axios.request` * Minor refactoring on the unit tests of `RulesEngine` to use `describe` blocks and `it()` instead of `test()` for consistency. * Added missing dependency that got removed after merging. * Updated quotes model unit tests to match the new implementation of config.js * Updated comments in codebase. * Removed ``^` sign from dependency in package.json * Bump npm-check-updates from 3.2.1 to 3.2.2 (#88) Bumps [npm-check-updates](https://github.com/tjunnone/npm-check-updates) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/tjunnone/npm-check-updates/releases) - [Commits](https://github.com/tjunnone/npm-check-updates/compare/v3.2.1...v3.2.2) Signed-off-by: dependabot-preview[bot] * Bump eslint from 6.6.0 to 6.7.1 (#89) Bumps [eslint](https://github.com/eslint/eslint) from 6.6.0 to 6.7.1. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v6.6.0...v6.7.1) Signed-off-by: dependabot-preview[bot] * bugfix/1079 Extensions Longer Than 128 Chars (#90) - truncateExtension config - fix issues with standardJS * Dissasociated unit tests from the actual contents of file `config/rules.json`; (#92) Added a `rules.example.json` file. * bugfix/1085 Quote to Inactive Fsp (#91) - Proper generate request headers when from switch * mowdev-3411 * added more rules * Feature/846 async logging (#100) * Add file logging support in docker, update dependencies * Add back missing package after merge conflicts * Feature/update json rules engine (#101) * Simplified rules unit tests * Updated json-rules-engine * Updated code to use native json-rules-engine jsonpath syntax * Made linter happy. Removed jsonpath dependency. * Feature/test fx rules (#102) * Added skeleton for fx rules unit tests * Removed commented tests from original file * Update fx.test.js * Feature/846 async logging (#100) * Add file logging support in docker, update dependencies * Add back missing package after merge conflicts * Feature/update json rules engine (#101) * Simplified rules unit tests * Updated json-rules-engine * Updated code to use native json-rules-engine jsonpath syntax * Made linter happy. Removed jsonpath dependency. * Feature/test fx rules (#102) * Added skeleton for fx rules unit tests * Removed commented tests from original file * Update fx.test.js * added more rules and tests * test discard * test discard * test discard * updated dependencies (#105) * stripe off accept header for PUT requests * added package-lock.json * Feature/1003 add container scans (#103) * Add anchore image scanning, update circleci config * Fix config.yml validity issues * Bump package version, ensure latest deps are installed * Feature/1047 improve test coverage (#108) * Add unit tests to bring coverage up to 90%+ remove redundant nyc config Set up dir structure for tests Set up dir structure for tests Add inspect util for ease of testing working on quotes error test Add istanbul ignore comments for mockgen only files working on health check mocks Working on config mocks Add bulk quotes not implemented tests Working on health check tests Working on health check tests remove unused comments working on quotes test working on config default tests working on utils tests working on utils tests find and replace all stack inspection find and replace all stack inspection Working on quote tests Move http into its own library for ease of mocking Move http into its own library for ease of mocking fix existing tests once mocking out http add tests for handleException add tests for handleException add tests for handleException finish getting model testing up to scratch fix missing conditions on rule engine tests Add tests for http refactor start script to improve tests work on server testing working on database mocking working on knex mocks working on knex mocks working on knex mocks working on knex mocks working on knex mocks replace err.stack || util.inspect(err) with getStackOrInspect work on quite tests work on quite tests finish work on cachedDatabase update dependencies, bump package version to 8.7.0 * remove unneeded test files * run standard --fix * bump package version to 8.7.1-snapshot * bump package version to 8.7.2-snapshot * added more rules * fixed the package.json version * fixed version number * fixed the Object.assign * removed rules.json * update package-lock.json * Attempt cache refresh * Replace audit:check with audit * Debug with verbose audit * Skip vulnerability check because of network errors * Skip vuln check step * downgrade helm version * #1147 - Update dependencies (#118) * Update sinon * Bump version to 8.8.0 * temp logging * renamed switchEndpoint to a better name * removed config from dockerfile * Fix for #1169 - GET /quotes for malformed ID error response is 1001 instead of 3xxx (#125) * Add quote ID validation in swagger.json * Update dependencies and fix unit test * Fix version * Added synchronous responses for rules engine invalid quote errors (#127) * Added synchronous responses for rules engine invalid quote errors * Corrected import * Corrected error variable name * Moved response handling out of model, into handlers * Fixed tests * added error code * added swagger changes * Bugfix/1172empty quote values (#128) * Added minLength of 1 for quoteId and transactionId for post quotes * Added a comment to remove the minLength property from quoteId and transactionId once the enjoi library has been fixed. * Upgrading version to v8.8.0-snapshot (#129) * Upgrading version to v8.8.0-snapshot and now we have test coverage >90% * Feature/1157 anchore report summary (#132) * Add anchore summary report upload * fix missing aws credentials * Update dependencies (#133) * added error handling when there are no active accounts * added error handling when there are no active accounts * added error handling when there are no active accounts * 893-UpdateRegexToValidateIncomingErrorCodeAtEndpointCallbackAndUpdateDependencies (#113) * Issue934-FixSetEnvVarRCAsBooleanInsteadOfString * WIP * mockConfig done * 893-AddSwaggerValidationForIncomingErrorCodePlusUnitTestChangeAndUpdateDependencies * Fix unit test, update dependencies plus Merge remote-tracking branch 'origin/893-ValidateIncomingErrorCodeAtErroCallbackEndpoint' into 893-ValidateIncomingErrorCodeAtErroCallbackEndpoint Co-authored-by: Georgi Georgiev Co-authored-by: Sam * fixed error responses sync and async * fixed the rounting problem with forex quotes * fixed the rounting problem with forex quotes * fixed the rounting problem with forex quotes * removed fspiop-uri header * removed fspiop-signature header * added one more error code to sync errors * added more error handling * Fix for #1173 - GET /quotes for unknown quote ID error response is 1001 instead of 3205 (#139) * Bump version to 9.0.0-snapshot * Fix response codes for PUT /quotes/{id} and PUT /quotes/{id}/error from 202 to 200 * Update dependencies. Freeze json-rules-engine due to breaking changes * Bump version to 9.1.0 * Remove hard-coded response codes in test * Return error 3000 - Generic client error and not 1001 on 404 errors * Update dependencies * Fix span bug * Update cs-shared * Upgrade to Node 12.16.0 LTS version (#150) - Updated CircleCI and Docker scripts to use Node 12.16.0 LTS version. - Updated dependencies * Added updated Mojaloop license (#151) * Added updated Mojaloop license (#152) * Hotfix: Fix startup failure error (#153) * Lock hapi version * Resolve audit issue, temporarily * Fix/1107 circleci deploy (#154) * remove sensitive notes * resolve npm audit issues * temp disable some cicd steps for speed up tests * fix missing aws config * Add parameters into orb config * Updating deploy config * helm deploy fixes * temporarily disable the coverage checks * replace inline deployment orb with orb reference * update deploy orb to v0.1.1 * removing duplicate configs * working on helm config * bump orb version to 0.1.4 * Working on executor config * Working on executor config * fix helm set values * more work on helm set values * more work on helm set values * Reenable skipped ci steps * bump package version to 9.2.2-snapshot, add hapi to the audit fix * Fixed /quote/\{id\}/error destination (#156) * Updated package version (#157) * Updated package version * Updated dependencies (#158) * updated to newly released version of event-sdk * updated dependencies and version * Feature/updating dependencies (#159) * updated to newly released version of event-sdk * updated dependencies and version * updated dependencies * #1178: Bug fixes for POST /quotes with unknown destination FSP (#160) * Validate that FSP Ids in headers and payload match for both payerfsp and payeefsp * Hotfix: Revert #1178 changes (#161) * Revert #1178 changes. Update depenedencies. Bump version * Undo version bump * Bugfix/restore handle quote error headers (#168) * Modified `forwardQuoteUpdate` so it handles special cases where it doesn't need to modify/set the headers. * Bumped to 9.3.4-snapshot; Added myself to the hall of fame. * Updated unit tests. * Changed bumped version to 9.4.0 to cope with the current versioning status. * Changed the places where the sendErrorCallback is called with `true` flag. * run `npm run audit:resolve` and skipped for a week. * Do not modify headers in case they are only being relayed to another DFSP. * Do not delete `FSPIOP-Signature` header unless if `modifyHeaders` is `true`. * Store extensionLists for quote requests and responses. (#184) * store extension list items for quote requests and responses * Adding unit test coverage for quote request and response extensionList saving to database * postpone audit failures * attempt to resolve further audit issues * Delete package-lock.json * another attempt to resolve audit issues * Bump package version * Proposed code changes for extensionLists PR (#185) * Proposed code changes for extensionLists PR * Lint Co-authored-by: Matt Kingston * Feature/otc 218 enhance post quote partyIdInfo with extension list (#190) * Added the extension list under the partyidinfo obj * OTC-218 Changes: Enhanced Post Quotes on quoting service to handle extension lists under partyId info Updated dependencies Postponed audit issue * OTC-218 Changes: Enhanced Post Quotes on quoting service to handle extension lists under partyId info * Add custom mojaloop policy for evaluating anchore-cli scans (#192) * Update dependencies (#200) * Update dependencies * Temporarily resolve audit issues * Hotfix for docker image to support async logging (#202) - Added async logging support to DockerFile - Updated dependencies for Jest - Fixed vulnerability issues - Bumped version to v10.1.1 * Merged `master` into this branch. * added JWS support for switch generated msg (#203) * added JWS support for switch generated msg * added unit tests * added coverage tests * fix audit issues * removed un-necessary header fix * added a valid default private key * added a default private key * not modify request in jwsSigner * fixed the version issue * bumped up the version * bumped up the version Co-authored-by: Shashi * fixed the bug with createQuoteExtensions * Fixed the arguments passed to `createQuoteExtensions`. (#213) * Fixed the arguments passed to `createQuoteExtensions`. * Updated expected error message in unit test. * fixed issue with createQuoteExtension * Fixed issue with `createQuoteExtension` (#214) * Revert change of the error message as it breaks tests. * Updated versions for error-handler, etc... (#218) * Change CI/CD notifications to their own slack channel, bump package to 10.3.1 (#219) * Fix DB transaction leaks. Update unit tests (#220) - Fixed DB transaction/connection leaks - Updated unit tests - Bumped version * Feature/validation for name place accents (#221) * updated to newly released version of event-sdk * updated dependencies and version * updates to migrate quoting api to use openapi-backend create openapi >= 3.0 swagger updated dependencies added new routes converted server to use new libraries golden path tests pass coverage may need some attention * added production to quotes audit checks * fixed incorrect case for file path * Updated code coverage * update of dependencies * error handling dependency update * updated dependency * Updated python in Circle CI (#222) * updated to newly released version of event-sdk * updated dependencies and version * updates to migrate quoting api to use openapi-backend create openapi >= 3.0 swagger updated dependencies added new routes converted server to use new libraries golden path tests pass coverage may need some attention * added production to quotes audit checks * fixed incorrect case for file path * Updated code coverage * update of dependencies * error handling dependency update * updated dependency * Changes: Updated python in circle CI * Updated dependencies and version for issue: https://github.com/mojaloop/project/issues/1378 (#223) * Aligned an error message with the master branch to match Postman test's assertions. * Fixed some npm vulnerabilities and skipped the rest. * Updated circle CI config according to master branch. * Removed `quoteId` from error log message as it causes error due its exceeding length. * Removed `quoteId` from error log message as it causes error due its exceeding length. (#224) * fixed error message * Bugfix/1385 fix post quotes header (#225) * updated to newly released version of event-sdk * updated dependencies and version * updated to remove accept header from PUT quotes callback * fix error message (#226) * fix error message * fix error message Co-authored-by: Shashi * Bugfix/fix participant lookup to use currency (#227) * updated to newly released version of event-sdk * updated dependencies and version * fix for accept header and content-type header versions being hardcoded * Bugfix/fix participant lookup to use currency (#228) * updated to newly released version of event-sdk * updated dependencies and version * fix for accept header and content-type header versions being hardcoded * updated participant lookup to validate against the participant and participant currency table to validate that the participant is active as well as their currency account * Bugfix/fix participant lookup to use currency (#230) * updated to newly released version of event-sdk * updated dependencies and version * fix for accept header and content-type header versions being hardcoded * updated participant lookup to validate against the participant and participant currency table to validate that the participant is active as well as their currency account * updated the order the sql is run in, seems to give and issue during testing * Bugfix/fix participant lookup to use currency (#231) Fix for createPartyQuote not passing all values to getParticipant * Feature/1468 support for bulk quotes post passthrough (#233) * updated to newly released version of event-sdk * updated dependencies and version * added support for bulk quotes post functionality updated dependencies to fix audit issues * added put, and get functionality for bulk quotes * Fix log text * added the put bulkQuotes error endpoint * updated according to stevens comments * removed unnecessary await * removed the await * awaits need to be there for audits * fixes for error handling according to @oderayi to handle exceptions in model instead of throwing it up to handler * #1484: Update FSPIOP API version (#235) * Update FSPIOP API version * Update src/interface/swagger.json Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * Update API description * Attempt to fix 'jest not found' error in circleci * Attempt to fix 'jest not found' error in circleci * Lock version update for jest and jest-unit, restore npm scripts * Update jest and jest-junit * Update src/interface/swagger.json Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * Bump version in attempt to bypass ci bug with caches Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * Add ISO test currencies (XTS, XXX) (#238) * Add ISO test currencies * Bump package version * added test currencies * resolve audit issues * fix audit issues * fix audit issues * Convert handlers to async, update deps, and bump version (#239) * Feature/#1615 content headers (#240) * added support for resource versions * updated dependencies Co-authored-by: Valentin * fixed resource api version to be changed only if message originates from the switch (#241) Co-authored-by: Valentin * updated dependencies and removed old audit records (#243) * Updated to cater for spans finishing early (#244) * updated dependencies and removed old audit records * updated to cater for parent spans finishing before the span can be closed and fixed tests * fixing tests and some code found during testing * fixes (#245) * updated dependencies and removed old audit records * updated to cater for parent spans finishing before the span can be closed and fixed tests * fixing tests and some code found during testing * needed to handle error in the model as the handler has already processed * #1456: Feature/docker config fixes (#247) * Update docker configs with master, bump patch version, update dependencies, and fix linting errors with Standard * Update tests * Clean up * Clean up * validate dfsps in payload for simple routing mode (#248) * #1875: Replace wildcard routes with explicit routes. (#249) * Replace wildcard routes with explicit routes. Add hapi-swagger for API documentation (swagger). Update dependencies. Bump patch version * Fix dependencies * chore: update license file (#251) * #1885: Add API documentation library (#250) * Add API documentation endpoints * Update dependencies * Resolve audit * Force update event-stream (Widdershins dep) due to license audit issues * [Security] Bump node-notifier from 8.0.0 to 8.0.1 (#252) Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1. **This update includes a security fix.** - [Release notes](https://github.com/mikaelbr/node-notifier/releases) - [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md) - [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> * [Security] Bump axios from 0.21.0 to 0.21.1 (#255) Bumps [axios](https://github.com/axios/axios) from 0.21.0 to 0.21.1. **This update includes a security fix.** - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v0.21.1/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.21.0...v0.21.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> * [Security] Bump urijs from 1.19.2 to 1.19.5 (#254) Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.2 to 1.19.5. **This update includes a security fix.** - [Release notes](https://github.com/medialize/URI.js/releases) - [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md) - [Commits](https://github.com/medialize/URI.js/compare/v1.19.2...v1.19.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * feat(ci/cd): add pr title check (#256) * chore: adding codeowners file (#257) * chore: maintenance upgrades, audit check resolve update (#258) * chore: adding codeowners file * chore: maintenance upgrades, audit check resolve update * fix(headers)!: made fspiop-destination header mandatory (#259) * fix(headers) ! :made fspiop-destination header mandatory * added unit test * added unit test * [Security] Bump urijs from 1.19.5 to 1.19.6 (#260) Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.5 to 1.19.6. **This update includes a security fix.** - [Release notes](https://github.com/medialize/URI.js/releases) - [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md) - [Commits](https://github.com/medialize/URI.js/compare/v1.19.5...v1.19.6) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> * fix(security): Bump y18n from 3.2.1 to 3.2.2 (#261) Bumps [y18n](https://github.com/yargs/y18n) from 3.2.1 to 3.2.2. **This update includes a security fix.** - [Release notes](https://github.com/yargs/y18n/releases) - [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md) - [Commits](https://github.com/yargs/y18n/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * fix(security): Bump djv from 2.1.2 to 2.1.4 (#263) Bumps [djv](https://github.com/korzio/djv) from 2.1.2 to 2.1.4. - [Release notes](https://github.com/korzio/djv/releases) - [Changelog](https://github.com/korzio/djv/blob/master/CHANGELOG.md) - [Commits](https://github.com/korzio/djv/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: #2103 fix subid functionality in POST quotes request (#264) * Fixed issue with subId * Bumped up the version and postponed the audits * Fixed unit test * Update src/data/database.js Co-authored-by: Lewis Daly Co-authored-by: Lewis Daly * feat(#2119): fixes for updated for AJV error objects change (#265) - Including new release of Central-services-error-handling: https://github.com/mojaloop/central-services-error-handling/releases/tag/v11.2.0 - Upgraded dependencies - Added AJV as it was a "peer dependency" - Bump to version - Updated audit-resolve for known security issue * fix(#2182): regex validations against swagger interface spec no longer working (#267) - Updated central-services-shared dependency - Bump to version - Audit-resolve issues * fix: helm release v12.1.0 (#269) - Updated dependencies - Bump to patch level - Standardised npm lint script - Fixes for audit issues * [Security] Bump hosted-git-info from 2.8.8 to 2.8.9 (#266) Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9. **This update includes a security fix.** - [Release notes](https://github.com/npm/hosted-git-info/releases) - [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md) - [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> * chore: helm release v12.1.0 (#270) - updated missing dependency updates due to ncurc - 'allow.auto.create.topics=true' had been added to Kafka Consumer configs. This will enable Kafka Consumers to trigger auto creation of topics, ref: https://github.com/edenhill/librdkafka/releases/tag/v1.5.0. * fix(mojaloop/project#2246): updated dependency version (#272) -Bumped Version -Fixed pre-commit task, misspelling Co-authored-by: JoNel * fix(#2358): firstname, middlename and lastname regex not supporting myanmar script unicode strings (#278) * fix(#2358): firstname, middlename and lastname regex not supporting myanmar script unicode strings [#2358](https://github.com/mojaloop/project/issues/2358) - Updated regex to match [\w](https://unicode.org/reports/tr18/#word) (used by the [Mojaloop Specification](https://github.com/mojaloop/mojaloop-specification/blob/master/fspiop-api/documents/v1.1-document-set/fspiop-v1.1-openapi3.yaml#L2347)) based on mappings to the [ECMAScript](https://262.ecma-international.org/9.0/#sec-runtime-semantics-unicodematchproperty-p) regex specification. - Added unit test for post quotes endpoint with additional asian (Myanmar) unicode characters added to middleName - Bump to patch version - Updated dependencies to the latest version - Fixed audit-resolve issues: ```text -------------------------------------------------- tar needs your attention. [ high ] Arbitrary File Creation/Overwrite due to insufficient absolute path sanitization vulnerable versions <3.2.2 || >=4.0.0 <4.4.14 || >=5.0.0 <5.0.6 || >=6.0.0 <6.1.1 found in: - dependencies: @mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar [ high ] Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning vulnerable versions <3.2.3 || >=4.0.0 <4.4.15 || >=5.0.0 <5.0.7 || >=6.0.0 <6.1.2 found in: - dependencies: @mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar ``` > Outcome: Fixed ```text -------------------------------------------------- yargs-parser needs your attention. [ low ] Prototype Pollution vulnerable versions <13.1.2 || >=14.0.0 <15.0.1 || >=16.0.0 <18.1.2 found in: - dependencies: @mojaloop/central-services-shared>widdershins>yargs>yargs-parser ``` > Outcome: Ignored for a week ```text -------------------------------------------------- sanitize-html needs your attention. [ moderate ] Improper Input Validation vulnerable versions <2.3.1 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html [ moderate ] Improper Input Validation vulnerable versions <2.3.2 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html ``` > Outcome: Ignored for a week * chore(#864): change instanbul to nyc for coverage on all projects (#279) chore(#864): change instanbul to nyc for coverage on all projects - removed .ncurc.yml as code-coverage is configured in the jest.config.js - fixes for audit resolve ```text -------------------------------------------------- yargs-parser needs your attention. [ low ] Prototype Pollution vulnerable versions <13.1.2 || >=14.0.0 <15.0.1 || >=16.0.0 <18.1.2 found in: - dependencies: @mojaloop/central-services-shared>widdershins>yargs>yargs-parser ``` > Outcome: Ignored for a week > Impact: Minimal as this is used to render documentation end-point ```text -------------------------------------------------- sanitize-html needs your attention. [ moderate ] Improper Input Validation vulnerable versions <2.3.1 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html [ moderate ] Improper Input Validation vulnerable versions <2.3.2 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html ``` > Outcome: Ignored for a week > Impact: Minimal as this is used to render documentation end-point * fix(mojaloop/#2439): quoting-service-model.validatequoterequest-doesnt-perform-correct-validation (#280) fix([mojaloop/#2439](https://github.com/mojaloop/project/issues/2439)): quoting-service model.validateQuoteRequest doesn't perform correct validation when simpleRoutingMode is TRUE - added typesafe checks for validate quote request logic - added devspace patterns to gitignore - minor formatting of the serverStart unit tests for clarity - updated dependencies to latest version - added circleci config for automated releases - added standard-version dependency for automated releases - fixed audit resolve issues: ```text -------------------------------------------------- tar needs your attention. [ high ] Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning using symbolic links vulnerable versions <4.4.18 || >=5.0.0 <5.0.10 || >=6.0.0 <6.1.9 found in: - dependencies: @mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar [ high ] Arbitrary File Creation/Overwrite on Windows via insufficient relative path sanitization vulnerable versions <4.4.18 || >=5.0.0 <5.0.10 || >=6.0.0 <6.1.9 found in: - dependencies: @mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar ``` > Outcome: Fixed ```text -------------------------------------------------- yargs-parser needs your attention. [ low ] Prototype Pollution vulnerable versions <13.1.2 || >=14.0.0 <15.0.1 || >=16.0.0 <18.1.2 found in: - dependencies: @mojaloop/central-services-shared>widdershins>yargs>yargs-parser ``` > Outcome: Ignored for a week > Impact: Minimal as the dependencies are used for the Developer Documentation end-point ```text -------------------------------------------------- sanitize-html needs your attention. [ moderate ] Improper Input Validation vulnerable versions <2.3.1 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html [ moderate ] Improper Input Validation vulnerable versions <2.3.2 found in: - dependencies: @mojaloop/central-services-shared>shins>sanitize-html ``` > Outcome: Ignored for a week > Impact: Minimal as the dependencies are used for the Developer Documentation end-point * fix: updated circleci config to use the SHA1 hash of the last commit of the current build (#281) * chore(release): 12.0.8 [skip ci] * fix: circleci slack webhook typo fix (#282) * fixes for CI-CD typo image-scan failure on slack webhook * chore(release): 12.0.9 [skip ci] * chore: updated readme with automated-releases, potential-problems and additional-notes placeholder (#283) * updated readme with Automated Releases, Potential Problems and Additional Notes placeholder * fixed markdown lint issues for readme * chore(release): 12.0.10 [skip ci] * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * Fixed the tests * changed the way we add headers * refactoring * refactoring * removed the hardcoded headers * removed the hardcoded headers * updated README * fixed swagger * revert sync changes * revert sync changes * revert sync changes * revert sync changes * revert sync changes * revert sync changes * revert sync changes Co-authored-by: Juan Correa Co-authored-by: Georgi Georgiev Co-authored-by: Vassilis Barzokas Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: shashi165 Co-authored-by: Lewis Daly Co-authored-by: Matt Kingston Co-authored-by: Valentin Genev Co-authored-by: Kamuela Franco Co-authored-by: Steven Oderayi Co-authored-by: ndonnan Co-authored-by: Sam Co-authored-by: Rajiv Mothilal Co-authored-by: James Bush <37296643+bushjames@users.noreply.github.com> Co-authored-by: lazolalucas Co-authored-by: Miguel de Barros Co-authored-by: Adrian Enns Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> Co-authored-by: Valentin Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: vijayg10 <33152110+vijayg10@users.noreply.github.com> Co-authored-by: Johann Nel <29751181+JohannWNel@users.noreply.github.com> Co-authored-by: JoNel Co-authored-by: mojaloopci --- .circleci/config.yml | 569 +- .gitignore | 5 + .ncurc.json | 5 + CHANGELOG.md | 20 + CODEOWNERS | 38 + Dockerfile | 21 +- LICENSE.md | 10 + README.md | 190 +- audit-resolve.json | 84 +- config/default.json | 12 +- config/rules.example.json | 533 +- config/rules.json | 1 + docker-compose.yml | 2 + docker/central-ledger/default.json | 168 +- docker/ml-api-adapter/default.json | 39 +- jest.config.js | 13 +- package-lock.json | 17727 ++++++++++------ package.json | 125 +- secrets/jwsSigningKey.key | 27 + src/data/bulkQuotes.js | 4 +- src/data/bulkQuotes/{id}.js | 4 +- src/data/bulkQuotes/{id}/error.js | 4 +- src/data/cachedDatabase.js | 4 +- src/data/database.js | 183 +- src/data/quotes.js | 6 +- src/data/quotes/{id}.js | 4 +- src/data/quotes/{id}/error.js | 4 +- src/handlers/bulkQuotes.js | 43 +- src/handlers/bulkQuotes/{id}.js | 83 +- src/handlers/bulkQuotes/{id}/error.js | 42 +- src/handlers/health.js | 78 +- src/handlers/index.js | 50 + src/handlers/quotes.js | 9 +- src/handlers/quotes/{id}.js | 22 +- src/handlers/quotes/{id}/error.js | 9 +- src/handlers/routes.js | 133 + src/index.js | 39 + src/interface/QuotingService-swagger.yaml | 1677 ++ src/interface/swagger.json | 95 +- src/lib/config.js | 17 +- src/lib/http.js | 89 + src/lib/util.js | 178 +- src/model/bulkQuotes.js | 501 + src/model/quotes.js | 629 +- src/model/rules.js | 110 +- src/server.js | 180 +- test/unit/data/cachedDatabase.test.js | 191 + test/unit/data/database.test.js | 2340 ++ test/unit/handlers/bulkQuotes.test.js | 112 + test/unit/handlers/bulkQuotes/{id}.test.js | 147 + .../handlers/bulkQuotes/{id}/error.test.js | 113 + test/unit/handlers/health.test.js | 204 + test/unit/handlers/quotes.test.js | 110 + test/unit/handlers/quotes/{id}.test.js | 144 + test/unit/handlers/quotes/{id}/error.test.js | 113 + test/unit/lib/config.test.js | 115 + test/unit/lib/http.test.js | 80 + test/unit/lib/util.test.js | 570 + test/unit/model/bulkQuotes.test.js | 1022 + test/unit/model/quotes.test.js | 2923 ++- test/unit/model/rules.test.js | 545 +- test/unit/rules/fx.test.js | 714 + test/unit/server.test.js | 119 + test/unit/serverStart.test.js | 170 + test/util/helper.js | 62 +- 65 files changed, 24740 insertions(+), 8840 deletions(-) create mode 100644 .ncurc.json create mode 100644 CHANGELOG.md create mode 100644 CODEOWNERS create mode 100644 LICENSE.md create mode 100644 config/rules.json create mode 100644 secrets/jwsSigningKey.key create mode 100644 src/handlers/index.js create mode 100644 src/handlers/routes.js create mode 100644 src/index.js create mode 100644 src/interface/QuotingService-swagger.yaml create mode 100644 src/lib/http.js create mode 100644 src/model/bulkQuotes.js create mode 100644 test/unit/data/cachedDatabase.test.js create mode 100644 test/unit/data/database.test.js create mode 100644 test/unit/handlers/bulkQuotes.test.js create mode 100644 test/unit/handlers/bulkQuotes/{id}.test.js create mode 100644 test/unit/handlers/bulkQuotes/{id}/error.test.js create mode 100644 test/unit/handlers/health.test.js create mode 100644 test/unit/handlers/quotes.test.js create mode 100644 test/unit/handlers/quotes/{id}.test.js create mode 100644 test/unit/handlers/quotes/{id}/error.test.js create mode 100644 test/unit/lib/config.test.js create mode 100644 test/unit/lib/http.test.js create mode 100644 test/unit/lib/util.test.js create mode 100644 test/unit/model/bulkQuotes.test.js create mode 100644 test/unit/rules/fx.test.js create mode 100644 test/unit/server.test.js create mode 100644 test/unit/serverStart.test.js diff --git a/.circleci/config.yml b/.circleci/config.yml index dd20f506..956f96ba 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,17 +1,23 @@ -# CircleCI v2 Config -version: 2 +# CircleCI v2.1 Config +version: 2.1 -defaults_working_directory: &defaults_working_directory - working_directory: /home/circleci/project - -defaults_docker_node: &defaults_docker_node - docker: - - image: node:10.15.3-alpine - -defaults_docker_helm_kube: &defaults_docker_helm_kube - docker: - - image: hypnoglow/kubernetes-helm +## +# orbs +# +# Orbs used in this pipeline +### +orbs: + anchore: anchore/anchore-engine@1.6.6 + deploy-kube: mojaloop/deployment@0.1.6 + slack: circleci/slack@3.4.2 + pr-tools: mojaloop/pr-tools@0.1.10 + github-release: h-matsuo/github-release@0.1.3 +## +# defaults +# +# YAML defaults templates, in alphabetical order +## defaults_Dependencies: &defaults_Dependencies | apk --no-cache add git apk --no-cache add ca-certificates @@ -23,14 +29,14 @@ defaults_Dependencies: &defaults_Dependencies | npm install -g node-gyp defaults_awsCliDependencies: &defaults_awsCliDependencies | + apk upgrade --no-cache apk --no-cache add \ - python \ - py-pip \ + python3 \ + py3-pip \ groff \ less \ mailcap - pip install --upgrade awscli==1.14.5 s3cmd==2.0.1 python-magic - apk -v --purge del py-pip + pip3 install --upgrade pip awscli==1.14.5 s3cmd==2.0.1 python-magic defaults_license_scanner: &defaults_license_scanner name: Install and set up license-scanner @@ -38,119 +44,37 @@ defaults_license_scanner: &defaults_license_scanner git clone https://github.com/mojaloop/license-scanner /tmp/license-scanner cd /tmp/license-scanner && make build default-files set-up -defaults_Environment: &defaults_environment - name: Set default environment - command: | - echo "Nothing to do here right now...move along!" -defaults_build_docker_login: &defaults_build_docker_login - name: Login to Docker Hub - command: | - docker login -u $DOCKER_USER -p $DOCKER_PASS -defaults_build_docker_build: &defaults_build_docker_build - name: Build Docker $CIRCLE_TAG image - command: | - echo "Building Docker image: $CIRCLE_TAG" - docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . -defaults_build_docker_build_release: &defaults_build_docker_build_release - name: Build Docker $RELEASE_TAG image - command: | - echo "Building Docker image: $RELEASE_TAG" - docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG . -defaults_build_docker_publish: &defaults_build_docker_publish - name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub - command: | - echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG" - docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG -defaults_build_docker_publish_release: &defaults_build_docker_publish_release - name: Publish Docker image $RELEASE_TAG tag to Docker Hub - command: | - echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG" - docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG -defaults_deploy_prequisites: &defaults_deploy_prequisites - name: Copy deployment pre-requisites from S3 bucket - command: | - if [ -z "$K8_USER_TOKEN" ]; - then - echo "Copying K8 keys into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS folder" - mkdir $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_KEY_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/ - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_CERT_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/ - else - echo "Skipping K8 keys into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS folder" - fi - echo "Copying Helm value file into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM folder for $K8_RELEASE_NAME release" - mkdir $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/ -defaults_deploy_config_kubernetes_cluster: &defaults_deploy_config_kubernetes_cluster - name: Configure Kubernetes cluster - command: | - echo "Configure Kubernetes cluster ${K8_CLUSTER_NAME}" - kubectl config set-cluster $K8_CLUSTER_NAME --server=$K8_CLUSTER_SERVER --insecure-skip-tls-verify=true -defaults_deploy_config_kubernetes_credentials: &defaults_deploy_config_kubernetes_credentials - name: Configure Kubernetes credentails - command: | - echo "Configure Kubernetes credentials ${K8_USER_NAME}" - if [ ! -z "$K8_USER_TOKEN" ]; - then - echo "Configure Kubernetes credentials ${K8_USER_NAME} using Token" - kubectl config set-credentials $K8_USER_NAME --token=$K8_USER_TOKEN - else - echo "Configure Kubernetes credentials ${K8_USER_NAME} using Certs" - kubectl config set-credentials $K8_USER_NAME --client-certificate=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_CERT_FILENAME --client-key=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_KEY_FILENAME - fi -defaults_deploy_config_kubernetes_context: &defaults_deploy_config_kubernetes_context - name: Confi gure Kubernetes context - command: | - echo "Configure Kubernetes context ${K8_CLUSTER_NAME}" - kubectl config set-context $K8_CLUSTER_NAME --cluster=$K8_CLUSTER_NAME --user=$K8_USER_NAME --namespace=$K8_NAMESPACE -defaults_deploy_set_kubernetes_context: &defaults_deploy_set_kubernetes_context - name: Set Kubernetes context - command: | - echo "Configure Kubernetes context ${K8_CLUSTER_NAME}" - kubectl config use-context $K8_CLUSTER_NAME -defaults_deploy_configure_helm: &defaults_deploy_configure_helm - name: Configure Helm - command: | - helm init --client-only -defaults_deploy_install_or_upgrade_helm_chart: &defaults_deploy_install_or_upgrade_helm_chart - name: Install or Upgrade Helm Chart - command: | - echo "Install or Upgrade Chart ${K8_RELEASE_NAME} for Docker Image ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG}" - if [ -z "$(helm list -q | grep -E "^${K8_RELEASE_NAME}$")" ] && [ "$(helm list -q | grep -E "^${K8_RELEASE_NAME}$")" != "Error: Unauthorized" ]; - then - echo "Installing ${K8_RELEASE_NAME} new release" - helm install --namespace=$K8_NAMESPACE --name=$K8_RELEASE_NAME --repo=$K8_HELM_REPO --version $K8_HELM_CHART_VERSION $HELM_VALUE_SET_VALUES -f $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $K8_HELM_CHART_NAME - else - echo "Upgrading ${K8_RELEASE_NAME} release" - helm upgrade $K8_RELEASE_NAME --repo=$K8_HELM_REPO --version $K8_HELM_CHART_VERSION --reuse-values $HELM_VALUE_SET_VALUES -f $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $K8_HELM_CHART_NAME - fi -defaults_slack_announcement: &defaults_slack_announcement - name: Slack announcement for tag releases - command: | - curl -X POST \ - $SLACK_WEBHOOK_ANNOUNCEMENT \ - -H 'Content-type: application/json' \ - -H 'cache-control: no-cache' \ - -d "{ - \"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\" - }" +## +# Executors +# +# CircleCI Executors +## +executors: + default-docker: + working_directory: /home/circleci/project + docker: + - image: node:12.16.1-alpine + + default-machine: + machine: + image: ubuntu-1604:201903-01 + +## +# Jobs +# +# A map of CircleCI jobs +## jobs: setup: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: name: Install general dependencies command: *defaults_Dependencies - - run: - <<: *defaults_environment - run: name: Access npm folder as root command: cd $(npm root -g)/npm - # - run: - # name: Install interledgerjs/five-bells-ledger-api-tests - # command: npm install github:interledgerjs/five-bells-ledger-api-tests - run: name: Update NPM install command: npm install @@ -158,23 +82,20 @@ jobs: name: Delete build dependencies command: apk del build-dependencies - save_cache: - key: dependency-cache-{{ checksum "package.json" }} + key: dependency-cache-{{ .Environment.CIRCLE_SHA1 }} paths: - node_modules test-unit: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: name: Install general dependencies command: *defaults_Dependencies - - run: - <<: *defaults_environment - restore_cache: keys: - - dependency-cache-{{ checksum "package.json" }} + - dependency-cache-{{ .Environment.CIRCLE_SHA1 }} - run: name: Create dir for test results command: mkdir -p ./test/results @@ -188,21 +109,18 @@ jobs: path: ./test/results test-coverage: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: name: Install general dependencies command: *defaults_Dependencies - - run: - <<: *defaults_environment - run: name: Install AWS CLI dependencies command: *defaults_awsCliDependencies - restore_cache: keys: - - dependency-cache-{{ checksum "package.json" }} + - dependency-cache-{{ .Environment.CIRCLE_SHA1 }} - run: name: Execute code coverage check command: npm -s run test:coverage-check @@ -221,60 +139,36 @@ jobs: else echo "Not a release (env CIRCLE_BRANCH != 'master'), skipping sending lcov.info to SonarQube." fi - test-integration: - machine: true - <<: *defaults_working_directory - steps: - - checkout - - run: - <<: *defaults_environment - - restore_cache: - key: dependency-cache-{{ checksum "package.json" }} - - run: - name: Create dir for test results - command: mkdir -p ./test/results - - run: - name: Execute integration tests - command: npm -s run test:integration - no_output_timeout: 25m - - store_artifacts: - path: ./test/results - prefix: test - - store_test_results: - path: ./test/results - vulnerability-check: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: + - checkout - run: name: Install general dependencies command: *defaults_Dependencies - - checkout - restore_cache: - key: dependency-cache-{{ checksum "package.json" }} + key: dependency-cache-{{ .Environment.CIRCLE_SHA1 }} - run: name: Create dir for test results command: mkdir -p ./audit/results - run: name: Check for new npm vulnerabilities - command: npm run audit:check --silent -- --json > ./audit/results/auditResults.json + command: npm run audit:check --silent -- --json > ./audit/results/auditResults.json - store_artifacts: path: ./audit/results prefix: audit audit-licenses: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: + - checkout - run: name: Install general dependencies command: *defaults_Dependencies - run: <<: *defaults_license_scanner - - checkout - restore_cache: - key: dependency-cache-{{ checksum "package.json" }} + key: dependency-cache-{{ .Environment.CIRCLE_SHA1 }} - run: name: Prune non-production packages before running license-scanner command: npm prune --production @@ -285,150 +179,219 @@ jobs: path: /tmp/license-scanner/results prefix: licenses - build-snapshot: - machine: true - <<: *defaults_working_directory + build: + executor: default-machine steps: - checkout - run: - <<: *defaults_environment - - run: - name: setup environment vars for SNAPSHOT release + name: Build Docker $CIRCLE_TAG image command: | - echo 'export RELEASE_TAG=$RELEASE_TAG_SNAPSHOT' >> $BASH_ENV - - run: - <<: *defaults_build_docker_login - - run: - <<: *defaults_build_docker_build + echo "Building Docker image: $CIRCLE_TAG" + docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . - run: - <<: *defaults_build_docker_build_release - - run: - <<: *defaults_build_docker_publish - - run: - <<: *defaults_build_docker_publish_release - - run: - <<: *defaults_slack_announcement + name: Save docker image to workspace + command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG + - persist_to_workspace: + root: /tmp + paths: + - ./docker-image.tar - build-hotfix: - machine: true - # <<: *default_env + license-scan: + executor: default-machine steps: - - checkout - - run: - <<: *defaults_environment - - run: - name: setup environment vars for HOTFIX release - command: | - echo 'export RELEASE_TAG=$RELEASE_TAG_PROD' >> $BASH_ENV + - attach_workspace: + at: /tmp - run: - <<: *defaults_build_docker_login + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-image.tar - run: - <<: *defaults_build_docker_build - - run: - <<: *defaults_build_docker_publish + <<: *defaults_license_scanner - run: - <<: *defaults_slack_announcement + name: Run the license-scanner + command: cd /tmp/license-scanner && mode=docker dockerImages=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG make run + - store_artifacts: + path: /tmp/license-scanner/results + prefix: licenses - build: - machine: true - # <<: *default_env + image-scan: + executor: anchore/anchore_engine steps: + - setup_remote_docker - checkout - run: - <<: *defaults_environment - - run: - name: setup environment vars for LATEST release + name: Install docker dependencies for anchore command: | - echo 'export RELEASE_TAG=$RELEASE_TAG_PROD' >> $BASH_ENV + apk add --update python3 py3-pip docker python3-dev libffi-dev openssl-dev gcc libc-dev make jq npm - run: - <<: *defaults_build_docker_login - - run: - <<: *defaults_build_docker_build + name: Install general dependencies + command: | + apk --no-cache add git + apk --no-cache add ca-certificates + apk --no-cache add curl + apk --no-cache add openssh-client + apk add --no-cache -t build-dependencies make gcc g++ python3 libtool autoconf automake + npm config set unsafe-perm true + npm install -g node-gyp - run: - <<: *defaults_build_docker_build_release + name: Install AWS CLI dependencies + command: *defaults_awsCliDependencies + - attach_workspace: + at: /tmp - run: - <<: *defaults_build_docker_publish + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-image.tar - run: - <<: *defaults_build_docker_publish_release + name: Download the mojaloop/ci-config repo + command: | + git clone https://github.com/mojaloop/ci-config /tmp/ci-config + # Generate the mojaloop anchore-policy + cd /tmp/ci-config/container-scanning && ./mojaloop-policy-generator.js /tmp/mojaloop-policy.json - run: - <<: *defaults_slack_announcement + name: Pull base image locally + command: | + docker pull node:12.16.1-alpine + # Analyze the base and derived image + # Note: It seems images are scanned in parallel, so preloading the base image result doesn't give us any real performance gain + - anchore/analyze_local_image: + # Force the older version, version 0.7.0 was just published, and is broken + anchore_version: v0.6.1 + image_name: "docker.io/node:12.16.1-alpine $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG" + policy_failure: false + timeout: '500' + # Note: if the generated policy is invalid, this will fallback to the default policy, which we don't want! + policy_bundle_file_path: /tmp/mojaloop-policy.json + - run: + name: Upload Anchore reports to s3 + command: | + aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive + aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" + aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive + - run: + name: Evaluate failures + command: /tmp/ci-config/container-scanning/anchore-result-diff.js anchore-reports/node_12.16.1-alpine-policy.json anchore-reports/${CIRCLE_PROJECT_REPONAME}*-policy.json + - slack/status: + fail_only: true + webhook: "$SLACK_WEBHOOK_ANNOUNCEMENT_CI_CD" + failure_message: 'Anchore Image Scan failed for: \`"${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG}"\`' + - store_artifacts: + path: anchore-reports - deploy-snapshot: - <<: *defaults_working_directory - <<: *defaults_docker_helm_kube + publish: + executor: default-machine steps: + - checkout + - attach_workspace: + at: /tmp - run: - <<: *defaults_environment + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-image.tar - run: - name: Install AWS CLI dependencies - command: *defaults_awsCliDependencies + name: Login to Docker Hub + command: docker login -u $DOCKER_USER -p $DOCKER_PASS - run: - name: setup environment vars for SNAPSHOT release + name: Re-tag pre built image command: | - echo 'export HELM_VALUE_FILENAME=$K8_HELM_VALUE_FILENAME_SNAPSHOT' >> $BASH_ENV - echo 'export K8_CLUSTER_SERVER=$K8_CLUSTER_SERVER_SNAPSHOT' >> $BASH_ENV - echo 'export K8_RELEASE_NAME=$K8_RELEASE_NAME_SNAPSHOT' >> $BASH_ENV - echo 'export K8_NAMESPACE=$K8_NAMESPACE_SNAPSHOT' >> $BASH_ENV - echo 'export K8_USER_NAME=$K8_USER_NAME_SNAPSHOT' >> $BASH_ENV - echo 'export K8_USER_TOKEN=$K8_USER_TOKEN_SNAPSHOT' >> $BASH_ENV - echo 'export K8_HELM_CHART_NAME=$K8_HELM_CHART_NAME_SNAPSHOT' >> $BASH_ENV - echo 'export K8_HELM_CHART_VERSION=$K8_HELM_CHART_VERSION_SNAPSHOT' >> $BASH_ENV - echo 'export HELM_VALUE_SET_VALUES="--set central.centralhub.centralledger.containers.api.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME --set central.centralhub.centralledger.containers.api.image.tag=$CIRCLE_TAG --set central.centralhub.centralledger.containers.admin.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME --set central.centralhub.centralledger.containers.admin.image.tag=$CIRCLE_TAG"' >> $BASH_ENV - - run: - <<: *defaults_deploy_prequisites - - run: - <<: *defaults_deploy_config_kubernetes_cluster - - run: - <<: *defaults_deploy_config_kubernetes_credentials + docker tag $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG - run: - <<: *defaults_deploy_config_kubernetes_context - - run: - <<: *defaults_deploy_set_kubernetes_context - - run: - <<: *defaults_deploy_configure_helm - - run: - <<: *defaults_deploy_install_or_upgrade_helm_chart + name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub + command: | + echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG" + docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG + echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG" + docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG + - slack/status: + webhook: "$SLACK_WEBHOOK_ANNOUNCEMENT" + success_message: '*"${CIRCLE_PROJECT_REPONAME}"* - Release \`"${CIRCLE_TAG}"\` \nhttps://github.com/mojaloop/"${CIRCLE_PROJECT_REPONAME}"/releases/tag/"${CIRCLE_TAG}"' deploy: - <<: *defaults_working_directory - <<: *defaults_docker_helm_kube + executor: deploy-kube/helm-kube + steps: + - checkout + - deploy-kube/setup_and_run: + helm_set_values: | + --set quoting-service.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME \ + --set quoting-service.image.tag=$CIRCLE_TAG + - slack/status: + fail_only: true + webhook: "$SLACK_WEBHOOK_ANNOUNCEMENT_CI_CD" + failure_message: 'Deployment failed for: \`"${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG}"\`' + + release: + executor: default-docker steps: - run: - <<: *defaults_environment - - run: - name: Install AWS CLI dependencies - command: *defaults_awsCliDependencies + name: Install general dependencies + command: *defaults_Dependencies + - checkout + - restore_cache: + keys: + - dependency-cache-{{ .Environment.CIRCLE_SHA1 }} - run: - name: setup environment vars for release + name: Configure git command: | - echo 'export HELM_VALUE_FILENAME=$K8_HELM_VALUE_FILENAME_PROD' >> $BASH_ENV - echo 'export K8_CLUSTER_SERVER=$K8_CLUSTER_SERVER_PROD' >> $BASH_ENV - echo 'export K8_RELEASE_NAME=$K8_RELEASE_NAME_PROD' >> $BASH_ENV - echo 'export K8_NAMESPACE=$K8_NAMESPACE_PROD' >> $BASH_ENV - echo 'export K8_USER_NAME=$K8_USER_NAME_PROD' >> $BASH_ENV - echo 'export K8_USER_TOKEN=$K8_USER_TOKEN_PROD' >> $BASH_ENV - echo 'export K8_HELM_CHART_NAME=$K8_HELM_CHART_NAME_PROD' >> $BASH_ENV - echo 'export K8_HELM_CHART_VERSION=$K8_HELM_CHART_VERSION_PROD' >> $BASH_ENV - echo 'export HELM_VALUE_SET_VALUES="--set central.centralhub.centralledger.containers.api.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME --set central.centralhub.centralledger.containers.api.image.tag=$CIRCLE_TAG --set central.centralhub.centralledger.containers.admin.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME --set central.centralhub.centralledger.containers.admin.image.tag=$CIRCLE_TAG"' >> $BASH_ENV + git config user.email ${GIT_CI_EMAIL} + git config user.name ${GIT_CI_USER} + git checkout ${CIRCLE_BRANCH} - run: - <<: *defaults_deploy_prequisites + name: Configure ssh + command: | + mkdir -p ~/.ssh + ssh-keyscan -p 443 ssh.github.com >> ~/.ssh/known_hosts + ssh-keyscan github.com >> ~/.ssh/known_hosts - run: - <<: *defaults_deploy_config_kubernetes_cluster + name: Generate changelog and bump package version + command: npm run release - run: - <<: *defaults_deploy_config_kubernetes_credentials + name: Push the release + command: git push --follow-tags origin ${CIRCLE_BRANCH} + + github-release: + executor: default-machine + steps: - run: - <<: *defaults_deploy_config_kubernetes_context + name: Install git + command: | + sudo apt-get update && sudo apt-get install -y git + - checkout - run: - <<: *defaults_deploy_set_kubernetes_context + name: Fetch updated release branch + command: | + git config user.email ${GIT_CI_EMAIL} + git config user.name ${GIT_CI_USER} + git fetch origin + git checkout origin/${CIRCLE_BRANCH} - run: - <<: *defaults_deploy_configure_helm + # Note: this is rather imperfect, but will do for now + name: Format the changelog into the github release body and get release tag + command: | + git diff --no-indent-heuristic master~1 HEAD CHANGELOG.md | sed -n '/^+[^+]/ s/^+//p' > /tmp/changes + echo 'export RELEASE_CHANGES=`cat /tmp/changes`' >> $BASH_ENV + echo 'export RELEASE_TAG=`cat package-lock.json | jq -r .version`' >> $BASH_ENV - run: - <<: *defaults_deploy_install_or_upgrade_helm_chart + name: check the release changes + command: | + echo "Changes are: ${RELEASE_CHANGES}" + - github-release/create: + github-token-variable: ${GITHUB_TOKEN} + tag: v${RELEASE_TAG} + title: v${RELEASE_TAG} Release + description: ${RELEASE_CHANGES} + file-path: CHANGELOG.md + - slack/status: + webhook: "$SLACK_WEBHOOK_ANNOUNCEMENT" + success_message: '*"${CIRCLE_PROJECT_REPONAME}"* - Release \`"v${RELEASE_TAG}"\` \nhttps://github.com/mojaloop/"${CIRCLE_PROJECT_REPONAME}"/releases/tag/"v${RELEASE_TAG}"' +## +# Workflows +# +# CircleCI Workflow config +## workflows: version: 2 build_and_test: jobs: + - pr-tools/pr-title-check: + context: org-global - setup: context: org-global filters: @@ -460,17 +423,6 @@ workflows: ignore: - /feature*/ - /bugfix*/ - # - test-integration: - # context: org-global - # requires: - # - setup - # filters: - # tags: - # only: /.*/ - # branches: - # ignore: - # - /feature*/ - # - /bugfix*/ - vulnerability-check: context: org-global requires: @@ -493,71 +445,82 @@ workflows: ignore: - /feature*/ - /bugfix*/ - - build-snapshot: + - build: context: org-global requires: - - setup - test-unit - # - test-coverage - # - test-integration - # - test-functional - # - test-spec + - test-coverage + - vulnerability-check + - audit-licenses filters: tags: - only: /v[0-9]+(\.[0-9]+)*\-snapshot/ + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: - /.*/ - - deploy-snapshot: + - license-scan: context: org-global requires: - - build-snapshot + - build filters: tags: - only: /v[0-9]+(\.[0-9]+)*\-snapshot/ + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: - /.*/ - - build: + - image-scan: context: org-global requires: - - setup - - test-unit - - test-coverage - - vulnerability-check - - audit-licenses - # - test-integration - # - test-functional - # - test-spec + - build filters: tags: - only: /v[0-9]+(\.[0-9]+)*/ + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: - /.*/ - - build-hotfix: + # New commits to master release automatically + - release: context: org-global requires: - - setup + - pr-tools/pr-title-check - test-unit - test-coverage - vulnerability-check - audit-licenses - # - test-integration - # - test-functional - # - test-spec + - license-scan + - image-scan filters: - tags: - only: /v[0-9]+(\.[0-9]+)*\-hotfix(\.[0-9]+)/ branches: - ignore: - - /.*/ - - deploy: + only: + - master + - /release\/v.*/ + - github-release: context: org-global requires: - - build + - release + filters: + branches: + only: + - master + - /release\/v.*/ + - publish: + context: org-global + requires: + - license-scan + - image-scan filters: tags: - only: /v[0-9]+(\.[0-9]+)*/ + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: + - /.*/ + # - deploy: + # context: org-global + # requires: + # - publish + # filters: + # tags: + # only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?/ + # branches: + # ignore: + # - /.*/ diff --git a/.gitignore b/.gitignore index 3ebccb51..6a1fd5f8 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,8 @@ typings/ # MacOs .[Dd][Ss]_[Ss]tore +.notes.md + +# https://devspace.sh/ +devspace* +.devspace/**.* diff --git a/.ncurc.json b/.ncurc.json new file mode 100644 index 00000000..5031238e --- /dev/null +++ b/.ncurc.json @@ -0,0 +1,5 @@ +{ + "reject": [ + "json-rules-engine" + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..23fcbdd5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +### [12.0.10](https://github.com/mojaloop/quoting-service/compare/v12.0.9...v12.0.10) (2021-09-01) + +### [12.0.9](https://github.com/mojaloop/quoting-service/compare/v12.0.8...v12.0.9) (2021-09-01) + + +### Bug Fixes + +* circleci slack webhook typo fix ([#282](https://github.com/mojaloop/quoting-service/issues/282)) ([3e6ac84](https://github.com/mojaloop/quoting-service/commit/3e6ac841727ffc5c133fee35387e4781c8253779)) + +### [12.0.8](https://github.com/mojaloop/quoting-service/compare/v12.0.7...v12.0.8) (2021-09-01) + + +### Bug Fixes + +* **mojaloop/#2439:** quoting-service-model.validatequoterequest-doesnt-perform-correct-validation ([#280](https://github.com/mojaloop/quoting-service/issues/280)) ([b0c2cdc](https://github.com/mojaloop/quoting-service/commit/b0c2cdc42422ecf604a58d48e9e5e9c2402d4341)), closes [mojaloop/#2439](https://github.com/mojaloop/quoting-service/issues/2439) [mojaloop/#2439](https://github.com/mojaloop/quoting-service/issues/2439) +* updated circleci config to use the SHA1 hash of the last commit of the current build ([#281](https://github.com/mojaloop/quoting-service/issues/281)) ([9ee10d7](https://github.com/mojaloop/quoting-service/commit/9ee10d72b5941b973e15e97633835aa6d34d20eb)) diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..2345393b --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,38 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +## These owners will be the default owners for everything in +## the repo. Unless a later match takes precedence, +## @global-owner1 and @global-owner2 will be requested for +## review when someone opens a pull request. +#* @global-owner1 @global-owner2 +* @vgenev @mdebarros @elnyry-sam-k @lewisdaly @oderayi @shashi165 @vijayg10 @eoln @bushjames + +## Order is important; the last matching pattern takes the most +## precedence. When someone opens a pull request that only +## modifies JS files, only @js-owner and not the global +## owner(s) will be requested for a review. +# *.js @js-owner + +## You can also use email addresses if you prefer. They'll be +## used to look up users just like we do for commit author +## emails. +#*.go docs@example.com + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. +# /build/logs/ @doctocat + +## The `docs/*` pattern will match files like +## `docs/getting-started.md` but not further nested files like +## `docs/build-app/troubleshooting.md`. +# docs/* docs@example.com + +## In this example, @octocat owns any file in an apps directory +## anywhere in your repository. +#apps/ @octocat + +## In this example, @doctocat owns any file in the `/docs` +## directory in the root of your repository. +#/docs/ @doctocat diff --git a/Dockerfile b/Dockerfile index 57985649..77eb70a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM node:10.15.3-alpine +FROM node:12.16.1-alpine as builder + WORKDIR /opt/quoting-service RUN apk add --no-cache -t build-dependencies git make gcc g++ python libtool autoconf automake \ @@ -8,12 +9,28 @@ RUN apk add --no-cache -t build-dependencies git make gcc g++ python libtool aut COPY package.json package-lock.json* /opt/quoting-service/ -RUN npm install --production +RUN npm install RUN apk del build-dependencies COPY config /opt/quoting-service/config COPY src /opt/quoting-service/src +FROM node:12.16.1-alpine + +WORKDIR /opt/quoting-service + +# Create empty log file & link stdout to the application log file +RUN mkdir ./logs && touch ./logs/combined.log +# Links combined to stdout +RUN ln -sf /dev/stdout ./logs/combined.log + +# Create a non-root user: ml-user +RUN adduser -D ml-user +USER ml-user + +COPY --chown=ml-user --from=builder /opt/quoting-service . +RUN npm prune --production + EXPOSE 3002 CMD ["npm", "run", "start"] diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..40350591 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,10 @@ +# LICENSE + +Copyright © 2020 Mojaloop Foundation + +The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 +(the "License") and you may not use these files except in compliance with the [License](http://www.apache.org/licenses/LICENSE-2.0). + +You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Unless required by applicable law or agreed to in writing, the Mojaloop files are 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](http://www.apache.org/licenses/LICENSE-2.0). diff --git a/README.md b/README.md index fa82b41a..b8a62563 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,211 @@ # Quoting Service + [![Git Commit](https://img.shields.io/github/last-commit/mojaloop/quoting-service.svg?style=flat)](https://github.com/mojaloop/quoting-service/commits/master) [![Git Releases](https://img.shields.io/github/release/mojaloop/quoting-service.svg?style=flat)](https://github.com/mojaloop/quoting-service/releases) [![Docker pulls](https://img.shields.io/docker/pulls/mojaloop/quoting-service.svg?style=flat)](https://hub.docker.com/r/mojaloop/quoting-service) -[![CircleCI](https://circleci.com/gh/mojaloop/quoting-service.svg?style=svg)](https://circleci.com/gh/mojaloop/quoting-service) +[![CircleCI](https://circleci.com/gh/mojaloop/quoting-service.svg?style=svg)](https://app.circleci.com/pipelines/github/mojaloop/quoting-service) + +The Quoting Service was donated by the Mowali project working in collaboration with Orange and MTN. The original author of this service is James Bush (james.bush@modusbox.com). -The Quoting Service was donated by the Mowali project working in collaboration with Orange and MTN. The Quoting service is now part of the Mojaloop project and deployment. -The service provided by the API resource /quotes is calculation of possible fees and FSP commission involved in performing an interoperable financial transaction. +The service provided by the API resource /quotes is calculation of possible fees and FSP commission involved in performing an interoperable financial transaction. Both the Payer and Payee FSP should calculate their part of the quote to be able to get a total view of all the fees and FSP commission involved in the transaction. -### Contents: +## Contents -- [Services Sequence overview](#services-sequence-overview) -- [Local Deployment](#local-deployment) +- [Quoting Service](#quoting-service) + - [Contents](#contents) + - [Services Sequence overview](#services-sequence-overview) + - [Running Locally](#running-locally) + - [Auditing Dependencies](#auditing-dependencies) + - [Container Scans](#container-scans) + - [Automated Releases](#automated-releases) + - [Potential problems](#potential-problems) + - [Additional Notes](#additional-notes) ## Services Sequence overview ![Quoting Service Sequence diagram](diagrams/quotingServiceSequences.svg) -* [Quoting Service Sequence diagram](diagrams/quotingServiceSequences.puml) +> [Quoting Service Sequence diagram](diagrams/quotingServiceSequences.puml) -## Local Deployment +## Running Locally Please follow the instruction in [Onboarding Document](onboarding.md) to setup and run the service locally. ## Auditing Dependencies -We use `npm-audit-resolver` along with `npm audit` to check dependencies for vulnerabilities, and keep track of resolved dependencies with an `audit-resolv.json` file. +We use `npm-audit-resolver` along with `npm audit` to check dependencies for node vulnerabilities, and keep track of resolved dependencies with an `audit-resolve.json` file. To start a new resolution process, run: + ```bash npm run audit:resolve ``` You can then check to see if the CI will pass based on the current dependencies with: + ```bash npm run audit:check ``` -And commit the changed `audit-resolv.json` to ensure that CircleCI will build correctly. -test \ No newline at end of file +And commit the changed `audit-resolve.json` to ensure that CircleCI will build correctly. + +## Container Scans + +As part of our CI/CD process, we use anchore-cli to scan our built docker container for vulnerabilities upon release. + +If you find your release builds are failing, refer to the [container scanning](https://github.com/mojaloop/ci-config#container-scanning) in our shared Mojaloop CI config repo. There is a good chance you simply need to update the `mojaloop-policy-generator.js` file and re-run the circleci workflow. + +For more information on anchore and anchore-cli, refer to: + +- [Anchore CLI](https://github.com/anchore/anchore-cli) +- [Circle Orb Registry](https://circleci.com/orbs/registry/orb/anchore/anchore-engine) + +## Automated Releases + +As part of our CI/CD process, we use a combination of CircleCI, standard-version +npm package and github-release CircleCI orb to automatically trigger our releases +and image builds. This process essentially mimics a manual tag and release. + +On a merge to master, CircleCI is configured to use the mojaloopci github account +to push the latest generated CHANGELOG and package version number. + +Once those changes are pushed, CircleCI will pull the updated master, tag and +push a release triggering another subsequent build that also publishes a docker image. + +### Potential problems + +- There is a case where the merge to master workflow will resolve successfully, triggering + a release. Then that tagged release workflow subsequently failing due to the image scan, + audit check, vulnerability check or other "live" checks. + + This will leave master without an associated published build. Fixes that require + a new merge will essentially cause a skip in version number or require a clean up + of the master branch to the commit before the CHANGELOG and bump. + + This may be resolved by relying solely on the previous checks of the + merge to master workflow to assume that our tagged release is of sound quality. + We are still mulling over this solution since catching bugs/vulnerabilities/etc earlier + is a boon. + +- It is unknown if a race condition might occur with multiple merges with master in + quick succession, but this is a suspected edge case. + + +## How to use quoting-service JSON rules +### About rules.json +The rules.json file acts as a rules engine and enables you to define arbitrary rules that will accept or reject quotes. A rule is defined as an object with a title, a conditions object, and an event object. A rule specifies that if certain conditions are met, then the specified event will be generated. + +The rules engine used by the quoting-service is an off-the-shelf rules engine, called json-rules-engine. For detailed information on how to write rules, see the [json-rules-engine documentation](https://github.com/CacheControl/json-rules-engine/blob/master/docs/rules.md). This page only focuses on those details that are relevant for adding support for new currencies. + +### Conditions +Conditions are a combination of facts, paths, operators, and values. + +Each rule's conditions must have either an all or an any operator at its root, containing an array of conditions. The all operator specifies that all conditions must be met for the rule to be applied. The any operator only requires one condition to be met for the rule to be applied. + +Operators within the individual conditions can take the following values: + + - `equal:` fact must equal value (string or numeric value) + - `notEqual:` fact must not equal value (string or numeric value) + - `in:` fact must be included in value (an array) + - `notIn:` fact must not be included in value (an array) + - `contains:` fact (an array) must include value + - `doesNotContain:` fact (an array) must not include value + +### Events +Event objects must have a type property, and an optional params property. There are two types of events: + + - `INTERCEPT_QUOTE`: Used for redirecting quote requests. + - `INVALID_QUOTE_REQUEST`: Used for validation rules. You do not have to use this type of event when adding support for new currencies. + +### Configuration – an example +``` + [ + { + "title": "This is UGX -> ZMW transfer rule", + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value":[ + "DFSPUGX", + "DFSPZMW" + ] + }, + { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency", + "operator": "equal", + "value": "UGX" + }, + { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency", + "operator": "equal", + "value": "ZMW" + } + ] + }, + "event":{ + "type": "INTERCEPT_QUOTE", + "params":{ + "rerouteToFsp": "DFSPUGX", + "additionalHeaders": { + "x-fspiop-sourcecurrency": "UGX", + "x-fspiop-destinationcurrency": "ZMW" + } + } + } + }, + { + "title": "Payee fsp should have only one active account", + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == \"POSITION\" && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == \"POSITION\" && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == \"POSITION\" && @.isActive == 1)]", + "operator": "isArray", + "value": true + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYEE_ERROR", + "message": "Payee FSP has more than 1 active currency account. Switch does not support more than 1 active currency account for Forex Requests" + } + } + } + ] + +``` +## Additional Notes + +N/A diff --git a/audit-resolve.json b/audit-resolve.json index 15adc748..4d12c141 100644 --- a/audit-resolve.json +++ b/audit-resolve.json @@ -1,14 +1,86 @@ { "decisions": { - "1184|npm-check-updates>pacote>make-fetch-happen>https-proxy-agent": { + "1673|@mojaloop/central-services-shared>data-urls>whatwg-url>lodash": { + "decision": "fix", + "madeAt": 1622648767062 + }, + "1673|@mojaloop/central-services-shared>openapi-backend>lodash": { + "decision": "fix", + "madeAt": 1622648767062 + }, + "1673|@mojaloop/central-services-shared>openapi-backend>mock-json-schema>lodash": { + "decision": "fix", + "madeAt": 1622648767062 + }, + "1673|@mojaloop/central-services-shared>shins>sanitize-html>lodash": { + "decision": "fix", + "madeAt": 1622648767062 + }, + "1500|@mojaloop/central-services-shared>widdershins>yargs>yargs-parser": { + "decision": "ignore", + "madeAt": 1632976633787, + "expiresAt": 1635568626757 + }, + "1675|@mojaloop/central-services-shared>shins>sanitize-html": { + "decision": "ignore", + "madeAt": 1632976636922, + "expiresAt": 1635568626757 + }, + "1676|@mojaloop/central-services-shared>shins>sanitize-html": { + "decision": "ignore", + "madeAt": 1632976636922, + "expiresAt": 1635568626757 + }, + "1693|@mojaloop/central-services-shared>shins>sanitize-html>postcss": { + "decision": "ignore", + "madeAt": 1623336829070, + "expiresAt": 1623941956342 + }, + "1770|@mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar": { + "decision": "fix", + "madeAt": 1628694530974 + }, + "1771|@mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar": { + "decision": "fix", + "madeAt": 1628694530974 + }, + "1780|@mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar": { + "decision": "fix", + "madeAt": 1630492425076 + }, + "1781|@mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>tar": { + "decision": "fix", + "madeAt": 1630492425076 + }, + "1002401|@mojaloop/central-services-shared>widdershins>yargs>string-width>strip-ansi>ansi-regex": { + "decision": "ignore", + "madeAt": 1634145313719, + "expiresAt": 1636737304260 + }, + "1002401|@mojaloop/central-services-shared>widdershins>yargs>cliui>string-width>strip-ansi>ansi-regex": { + "decision": "ignore", + "madeAt": 1634145313719, + "expiresAt": 1636737304260 + }, + "1002401|@mojaloop/event-sdk>grpc>@mapbox/node-pre-gyp>npmlog>gauge>wide-align>string-width>strip-ansi>ansi-regex": { + "decision": "ignore", + "madeAt": 1634145313719, + "expiresAt": 1636737304260 + }, + "1002865|@mojaloop/central-services-shared>shins>sanitize-html": { + "decision": "ignore", + "madeAt": 1634145316146, + "expiresAt": 1636737304260 + }, + "1002866|@mojaloop/central-services-shared>shins>sanitize-html": { "decision": "ignore", - "madeAt": 1571739084837, - "expiresAt": 1574331074508 + "madeAt": 1634145316146, + "expiresAt": 1636737304260 }, - "1184|npm-check-updates>pacote>npm-registry-fetch>make-fetch-happen>https-proxy-agent": { + "1003019|@mojaloop/central-services-shared>widdershins>yargs>yargs-parser": { "decision": "ignore", - "madeAt": 1571739084837, - "expiresAt": 1574331074508 + "madeAt": 1634145318834, + "expiresAt": 1636737304260 } }, "rules": {}, diff --git a/config/default.json b/config/default.json index 20dea4cb..067d7ee1 100644 --- a/config/default.json +++ b/config/default.json @@ -26,7 +26,15 @@ "SWITCH_ENDPOINT": "http://localhost:3001", "ERROR_HANDLING": { "includeCauseExtension": false, - "truncateCause": true + "truncateExtensions": true }, - "SIMPLE_ROUTING_MODE": true + "SIMPLE_ROUTING_MODE": true, + "ENDPOINT_SECURITY":{ + "JWS": { + "JWS_SIGN": false, + "FSPIOP_SOURCE_TO_SIGN": "switch", + "JWS_SIGNING_KEY_PATH": "secrets/jwsSigningKey.key" + } + }, + "API_DOCUMENTATION_ENDPOINTS": true } diff --git a/config/rules.example.json b/config/rules.example.json index 7e8b7e14..a9cf1505 100644 --- a/config/rules.example.json +++ b/config/rules.example.json @@ -3,32 +3,80 @@ "conditions": { "all": [ { - "fact": "json-path", - "params": { - "fact": "payload", - "path": "$.payload.extensionList[?(@.key == 'KYCPayerTier')].value" - }, - "operator": "deepEqual", - "value": [ "1" ] + "fact": "payer", + "path": "$.accounts", + "operator": "isArray", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_UNSUPPORTED_CURRENCY", + "message": "Payer does not have any active accounts" + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "payee", + "path": "$.accounts", + "operator": "isArray", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYEE_UNSUPPORTED_CURRENCY", + "message": "Payee does not have any active accounts" + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] }, { "fact": "payload", - "path": ".amount.currency", + "path": "$.amount.currency", "operator": "notIn", "value": { - "fact": "json-path", - "params": { - "fact": "payee", - "path": "$.payee.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" - } + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "EUR" } ] }, "event": { "type": "INTERCEPT_QUOTE", "params": { - "rerouteToFsp": "DFSPEUR" + "rerouteToFsp": "DFSPEUR", + "sourceCurrency": "EUR", + "rerouteToFspCurrency": "XOF", + "additionalHeaders": { + "x-fspiop-sourcecurrency": "EUR", + "x-fspiop-destinationcurrency": "XOF" + } } } }, @@ -36,24 +84,175 @@ "conditions": { "all": [ { - "fact": "json-path", - "params": { - "fact": "payload", - "path": "$.payload.extensionList[?(@.key == 'KYCPayerTier')].value" - }, - "operator": "notDeepEqual", - "value": [ "1" ] + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] }, { "fact": "payload", - "path": ".amount.currency", + "path": "$.amount.currency", "operator": "notIn", "value": { - "fact": "json-path", - "params": { - "fact": "payee", - "path": "$.payee.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" - } + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "XOF" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPEUR", + "sourceCurrency": "EUR", + "rerouteToFspCurrency": "XOF", + "additionalHeaders": { + "x-fspiop-sourcecurrency": "EUR", + "x-fspiop-destinationcurrency": "XOF" + } + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "XOF" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPXOF", + "sourceCurrency": "XOF", + "rerouteToFspCurrency": "EUR", + "additionalHeaders": { + "x-fspiop-sourcecurrency": "XOF", + "x-fspiop-destinationcurrency": "EUR" + } + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "EUR" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPXOF", + "sourceCurrency": "XOF", + "rerouteToFspCurrency": "EUR", + "additionalHeaders": { + "x-fspiop-sourcecurrency": "XOF", + "x-fspiop-destinationcurrency": "EUR" + } + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "payload", + "path": "$.amountType", + "operator": "equal", + "value": "SEND" + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_UNSUPPORTED_CURRENCY", + "message": "Requested currency not available for payer" + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "payload", + "path": "$.amountType", + "operator": "equal", + "value": "RECEIVE" + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" } } ] @@ -62,7 +261,285 @@ "type": "INVALID_QUOTE_REQUEST", "params": { "FSPIOPError": "PAYEE_UNSUPPORTED_CURRENCY", - "message": "The requested payee does not support the payment currency" + "message": "Requested currency not available for payee" + } + } + }, + { + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notEqual", + "value": { + "fact": "payload", + "path": "$.payer.partyIdInfo.fspId" + } + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_ERROR", + "message": "The payer FSP does not match the fspiop-source header" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payload", + "path": "$.payer.personalInfo.complexName.firstName", + "operator": "isString", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "MISSING_ELEMENT", + "message": "firstName is required" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payload", + "path": "$.payer.personalInfo.complexName.lastName", + "operator": "isString", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "MISSING_ELEMENT", + "message": "lastName is required" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payload", + "path": "$.payer.personalInfo", + "operator": "isObject", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "MISSING_ELEMENT", + "message": "PartyPersonalInfo is required" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payload", + "path": "$.payer.personalInfo.dateOfBirth", + "operator": "isString", + "value": false + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "MISSING_ELEMENT", + "message": "dateOfBirth is required" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)]", + "operator": "isArray", + "value": true + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_ERROR", + "message": "Payer should not have more than 1 currency account" + } + } + }, + { + "conditions": { + "all": [ + { + "any": [ + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)].currency" + } + } + ] + }, + { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'POSITION' && @.isActive == 1)]", + "operator": "isArray", + "value": true + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYEE_ERROR", + "message": "Payee should not have more than 1 currency account" } } } diff --git a/config/rules.json b/config/rules.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/config/rules.json @@ -0,0 +1 @@ +[] diff --git a/docker-compose.yml b/docker-compose.yml index 9325ac42..84611566 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,5 +9,7 @@ services: container_name: qs_quoting-service ports: - "3002:3002" + environment: + - CSL_LOG_TRANSPORT=file volumes: - ./docker/quoting-service/default.json:/opt/quoting-service/config/default.json diff --git a/docker/central-ledger/default.json b/docker/central-ledger/default.json index a0633542..f9f539fd 100644 --- a/docker/central-ledger/default.json +++ b/docker/central-ledger/default.json @@ -3,7 +3,7 @@ "HOSTNAME": "http://central-ledger", "DATABASE": { "DIALECT": "mysql", - "HOST": "central_ledger", + "HOST": "qs_mysql", "PORT": 3306, "USER": "central_ledger", "PASSWORD": "password", @@ -18,7 +18,10 @@ "CREATE_RETRY_INTERVAL_MILLIS": 200, "DEBUG": false }, - "RUN_MIGRATIONS": true, + "MIGRATIONS": { + "DISABLED": false, + "RUN_DATA_MIGRATIONS": true + }, "AMOUNT": { "PRECISION": 18, "SCALE": 4 @@ -30,20 +33,19 @@ "CONNECT_TIMEOUT": 45000, "RECONNECT_INTERVAL": 5000 }, - "DB_CONNECTION": { - "POOL_MIN": 10, - "POOL_MAX": 30 + "MONGODB": { + "DISABLED": true, + "URI": "mongodb://localhost:27017/mlos" + }, + "ERROR_HANDLING": { + "includeCauseExtension": true, + "truncateExtensions": false }, "HANDLERS": { "DISABLED": false, "API": { "DISABLED": false }, - "CRON": { - "DISABLED": false, - "TIMEXP": "*/10 * * * * *", - "TIMEZONE": "UTC" - }, "TIMEOUT": { "DISABLED": false, "TIMEXP": "*/15 * * * * *", @@ -76,6 +78,13 @@ ] }, "INTERNAL_TRANSFER_VALIDITY_SECONDS": "432000", + "ENABLE_ON_US_TRANSFERS": false, + "CACHE": { + "CACHE_ENABLED": false, + "MAX_BYTE_SIZE": 10000000, + "EXPIRES_IN_MS": 1000 + }, + "API_DOC_ENDPOINTS_ENABLED": true, "KAFKA": { "TOPIC_TEMPLATES": { "PARTICIPANT_TOPIC_TEMPLATE": { @@ -88,6 +97,104 @@ } }, "CONSUMER": { + "BULK": { + "PREPARE": { + "config": { + "options": { + "mode": 2, + "batchSize": 1, + "pollFrequency": 10, + "recursiveTimeout": 100, + "messageCharset": "utf8", + "messageAsJSON": true, + "sync": true, + "consumeTimeout": 1000 + }, + "rdkafkaConf": { + "client.id": "cl-con-bulk-prepare", + "group.id": "cl-group-bulk-prepare", + "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, + "socket.keepalive.enable": true + }, + "topicConf": { + "auto.offset.reset": "earliest" + } + } + }, + "PROCESSING": { + "config": { + "options": { + "mode": 2, + "batchSize": 1, + "pollFrequency": 10, + "recursiveTimeout": 100, + "messageCharset": "utf8", + "messageAsJSON": true, + "sync": true, + "consumeTimeout": 1000 + }, + "rdkafkaConf": { + "client.id": "cl-con-bulk-processing", + "group.id": "cl-group-bulk-processing", + "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, + "socket.keepalive.enable": true + }, + "topicConf": { + "auto.offset.reset": "earliest" + } + } + }, + "FULFIL": { + "config": { + "options": { + "mode": 2, + "batchSize": 1, + "pollFrequency": 10, + "recursiveTimeout": 100, + "messageCharset": "utf8", + "messageAsJSON": true, + "sync": true, + "consumeTimeout": 1000 + }, + "rdkafkaConf": { + "client.id": "cl-con-bulk-fulfil", + "group.id": "cl-group-bulk-fulfil", + "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, + "socket.keepalive.enable": true + }, + "topicConf": { + "auto.offset.reset": "earliest" + } + } + }, + "GET": { + "config": { + "options": { + "mode": 2, + "batchSize": 1, + "pollFrequency": 10, + "recursiveTimeout": 100, + "messageCharset": "utf8", + "messageAsJSON": true, + "sync": true, + "consumeTimeout": 1000 + }, + "rdkafkaConf": { + "client.id": "cl-con-bulk-get", + "group.id": "cl-group-bulk-get", + "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, + "socket.keepalive.enable": true + }, + "topicConf": { + "auto.offset.reset": "earliest" + } + } + } + }, "TRANSFER": { "PREPARE": { "config": { @@ -105,6 +212,7 @@ "client.id": "cl-con-transfer-prepare", "group.id": "cl-group-transfer-prepare", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -128,6 +236,7 @@ "client.id": "cl-con-transfer-get", "group.id": "cl-group-transfer-get", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -151,6 +260,7 @@ "client.id": "cl-con-transfer-fulfil", "group.id": "cl-group-transfer-fulfil", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -174,6 +284,7 @@ "client.id": "cl-con-transfer-position", "group.id": "cl-group-transfer-position", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -199,6 +310,7 @@ "client.id": "cl-con-transfer-admin", "group.id": "cl-group-transfer-admin", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -209,6 +321,27 @@ } }, "PRODUCER": { + "BULK": { + "PROCESSING": { + "config": { + "options": { + "messageCharset": "utf8" + }, + "rdkafkaConf": { + "metadata.broker.list": "kafka:9092", + "client.id": "cl-prod-bulk-processing", + "event_cb": true, + "dr_cb": true, + "socket.keepalive.enable": true, + "queue.buffering.max.messages": 10000000 + }, + "topicConf": { + "request.required.acks": "all", + "partitioner": "murmur2_random" + } + } + } + }, "TRANSFER": { "PREPARE": { "config": { @@ -224,7 +357,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } }, @@ -242,7 +376,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } }, @@ -260,7 +395,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } } @@ -280,7 +416,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } } @@ -300,7 +437,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } } diff --git a/docker/ml-api-adapter/default.json b/docker/ml-api-adapter/default.json index 0a1b3637..e8fe34ac 100644 --- a/docker/ml-api-adapter/default.json +++ b/docker/ml-api-adapter/default.json @@ -2,16 +2,31 @@ "PORT": 3000, "HOSTNAME": "http://ml-api-adapter", "ENDPOINT_SOURCE_URL": "http://central-ledger:3001/participants/{{fsp}}/endpoints", + "ENDPOINT_HEALTH_URL": "http://central-ledger:3001/health", "ENDPOINT_CACHE_CONFIG": { "expiresIn": 180000, "generateTimeout": 30000 }, - "ENDPOINT_SECURITY": { + "ENDPOINT_SECURITY":{ "TLS": { "rejectUnauthorized": true + }, + "JWS": { + "JWS_SIGN": false, + "FSPIOP_SOURCE_TO_SIGN": "switch", + "JWS_SIGNING_KEY_PATH": "secrets/jwsSigningKey.key" } }, + "MAX_CALLBACK_TIME_LAG_DILATION_MILLISECONDS": 200, "MAX_FULFIL_TIMEOUT_DURATION_SECONDS": 300, + "TRANSFERS": { + "SEND_TRANSFER_CONFIRMATION_TO_PAYEE": true + }, + "STRIP_UNKNOWN_HEADERS": false, + "ERROR_HANDLING": { + "includeCauseExtension": false, + "truncateExtensions": true + }, "AMOUNT": { "PRECISION": 10, "SCALE": 2 @@ -39,18 +54,6 @@ "GENERAL_TOPIC_TEMPLATE": { "TEMPLATE": "topic-{{functionality}}-{{action}}", "REGEX": "topic-(.*)-(.*)" - }, - "NOTIFICATION_TOPIC_TEMPLATE": { - "TEMPLATE": "topic-notification-event", - "REGEX": "topic-notification-event" - }, - "FULFIL_TOPIC_TEMPLATE": { - "TEMPLATE": "topic-transfer-fulfil", - "REGEX": "topic-transfer-fulfil" - }, - "GET_TRANSFERS_TOPIC_TEMPLATE": { - "TEMPLATE": "topic-transfer-get", - "REGEX": "topic-transfer-get" } }, "CONSUMER": { @@ -71,6 +74,7 @@ "client.id": "ml-con-notification-event", "group.id": "ml-group-notification-event", "metadata.broker.list": "kafka:9092", + "allow.auto.create.topics": true, "socket.keepalive.enable": true }, "topicConf": { @@ -96,7 +100,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } }, @@ -114,7 +119,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } }, @@ -132,7 +138,8 @@ "queue.buffering.max.messages": 10000000 }, "topicConf": { - "request.required.acks": "all" + "request.required.acks": "all", + "partitioner": "murmur2_random" } } } diff --git a/jest.config.js b/jest.config.js index cd8f1a7f..924d0a63 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,18 @@ - const path = require('path') module.exports = { + verbose: true, + collectCoverageFrom: [ + '**/src/**/**/*.js' + ], + coverageThreshold: { + global: { + statements: 90, + functions: 90, + branches: 90, + lines: 90 + } + }, globals: { __SRC__: path.resolve(__dirname, 'src'), __ROOT__: path.resolve(__dirname) diff --git a/package-lock.json b/package-lock.json index 64052737..53556ea5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2868 +1,4860 @@ { "name": "quoting-service", - "version": "8.4.0-snapshot", + "version": "12.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.14.5" } }, + "@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "dev": true + }, "@babel/core": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.4", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.4", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.3", - "@babel/types": "^7.6.3", - "convert-source-map": "^1.1.0", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", + "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "requires": { - "@babel/types": "^7.6.3", + "@babel/types": "^7.15.6", "jsesc": "^2.5.1", - "lodash": "^4.17.13", "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "@babel/helper-compilation-targets": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" } }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.15.4" } }, - "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", "dev": true, "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" + "@babel/types": "^7.15.4" } }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "@babel/helper-member-expression-to-functions": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "@babel/types": "^7.15.4" } }, - "@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", - "dev": true - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "@babel/helper-module-imports": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/types": "^7.15.4" } }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "@babel/helper-module-transforms": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" } }, - "@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "@babel/helper-optimise-call-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" + "@babel/types": "^7.15.4" } }, - "@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "@babel/helper-replace-supers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@grpc/proto-loader": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.2.tgz", - "integrity": "sha512-eBKD/FPxQoY1x6QONW2nBd54QUEyzcFP9FenujmoeDPy1rutVSHki1s/wR68F6O1QfCNDx+ayBH1O2CVNMzyyw==", - "requires": { - "lodash.camelcase": "^4.3.0", - "protobufjs": "^6.8.6" - } - }, - "@hapi/accept": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-3.2.3.tgz", - "integrity": "sha512-qEzsOJkCAJZxwj3iF83bSG9Lxy8Bpbrt8mRLNdvSALT6vlU2cYh6ZEHKEZPy4h/Mo31Su3j0rJgFF91+W1RWDQ==", - "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "8.x.x" - } - }, - "@hapi/address": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.2.tgz", - "integrity": "sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q==" - }, - "@hapi/ammo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-3.1.1.tgz", - "integrity": "sha512-NYFK27VSPGyQ/KmOQedpQH4PSjE7awLntepX68vrYtRvuJO21W1kX0bK2p3C+6ltUwtCQSvmNT8a4uMVAysC6Q==", - "requires": { - "@hapi/hoek": "8.x.x" + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, - "@hapi/b64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-4.2.1.tgz", - "integrity": "sha512-zqHpQuH5CBMw6hADzKfU/IGNrxq1Q+/wTYV+OiZRQN9F3tMyk+9BUMeBvFRMamduuqL8iSp62QAnJ+7ATiYLWA==", - "requires": { - "@hapi/hoek": "8.x.x" - } - }, - "@hapi/boom": { - "version": "7.4.11", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-7.4.11.tgz", - "integrity": "sha512-VSU/Cnj1DXouukYxxkes4nNJonCnlogHvIff1v1RVoN4xzkKhMXX+GRmb3NyH1iar10I9WFPDv2JPwfH3GaV0A==", - "requires": { - "@hapi/hoek": "8.x.x" - } - }, - "@hapi/bounce": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-1.3.2.tgz", - "integrity": "sha512-3bnb1AlcEByFZnpDIidxQyw1Gds81z/1rSqlx4bIEE+wUN0ATj0D49B5cE1wGocy90Rp/de4tv7GjsKd5RQeew==", - "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "^8.3.1" - } - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", - "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" - }, - "@hapi/call": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/call/-/call-5.1.1.tgz", - "integrity": "sha512-M6fC+9+K/ZB4hIdVQ8i0kc/6J5PWlW3PEWYKAAZpw0sk+28LiRTSF8BjOWwmiIjZWWs42AnEIiFJA0YrvcDnlw==", + "@babel/helper-simple-access": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "dev": true, "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "8.x.x" + "@babel/types": "^7.15.4" } }, - "@hapi/catbox": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-10.2.3.tgz", - "integrity": "sha512-kN9hXO4NYyOHW09CXiuj5qW1syc/0XeVOBsNNk0Tz89wWNQE5h21WF+VsfAw3uFR8swn/Wj3YEVBnWqo82m/JQ==", + "@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "dev": true, "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/joi": "16.x.x", - "@hapi/podium": "3.x.x" + "@babel/types": "^7.15.4" } }, - "@hapi/catbox-memory": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-4.1.1.tgz", - "integrity": "sha512-T6Hdy8DExzG0jY7C8yYWZB4XHfc0v+p1EGkwxl2HoaPYAmW7I3E59M/IvmSVpis8RPcIoBp41ZpO2aZPBpM2Ww==", - "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "8.x.x" - } + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" }, - "@hapi/content": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@hapi/content/-/content-4.1.0.tgz", - "integrity": "sha512-hv2Czsl49hnWDEfRZOFow/BmYbKyfEknmk3k83gOp6moFn5ceHB4xVcna8OwsGfy8dxO81lhpPy+JgQEaU4SWw==", - "requires": { - "@hapi/boom": "7.x.x" - } + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true }, - "@hapi/cryptiles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-4.2.1.tgz", - "integrity": "sha512-XoqgKsHK0l/VpqPs+tr6j6vE+VQ3+2bkF2stvttmc7xAOf1oSAwHcJ0tlp/6MxMysktt1IEY0Csy3khKaP9/uQ==", + "@babel/helpers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "dev": true, "requires": { - "@hapi/boom": "7.x.x" + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, - "@hapi/file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@hapi/file/-/file-1.0.0.tgz", - "integrity": "sha512-Bsfp/+1Gyf70eGtnIgmScvrH8sSypO3TcK3Zf0QdHnzn/ACnAkI6KLtGACmNRPEzzIy+W7aJX5E+1fc9GwIABQ==" - }, - "@hapi/formula": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-1.2.0.tgz", - "integrity": "sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA==" - }, - "@hapi/good": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@hapi/good/-/good-8.2.4.tgz", - "integrity": "sha512-Paj7BX4C295I+opJ5eIV0XvLhRPcKDLpP9RsnUWGXH/gLRi1SwVMOCYAqitSBjhYSIeZoq+jMmJn6+hUg4W3ug==", + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "requires": { - "@hapi/hoek": "8.x.x", - "@hapi/joi": "16.x.x", - "@hapi/oppsy": "2.x.x", - "pumpify": "1.x.x" - } - }, - "@hapi/hapi": { - "version": "18.4.0", - "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-18.4.0.tgz", - "integrity": "sha512-uk9zqknRLcNVQKgrPURm85DqkdroWP8eDRekh/IPoKvC4VjdZSn6EH2eUriOwyud/CldeBS3HDIJ/PtRj3VxDQ==", - "requires": { - "@hapi/accept": "3.x.x", - "@hapi/ammo": "3.x.x", - "@hapi/boom": "7.x.x", - "@hapi/bounce": "1.x.x", - "@hapi/call": "5.x.x", - "@hapi/catbox": "10.x.x", - "@hapi/catbox-memory": "4.x.x", - "@hapi/heavy": "6.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/joi": "15.x.x", - "@hapi/mimos": "4.x.x", - "@hapi/podium": "3.x.x", - "@hapi/shot": "4.x.x", - "@hapi/somever": "2.x.x", - "@hapi/statehood": "6.x.x", - "@hapi/subtext": "6.x.x", - "@hapi/teamwork": "3.x.x", - "@hapi/topo": "3.x.x" - }, - "dependencies": { - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" } } } }, - "@hapi/heavy": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-6.2.2.tgz", - "integrity": "sha512-PY1dCCO6dsze7RlafIRhTaGeyTgVe49A/lSkxbhKGjQ7x46o/OFf7hLiRqTCDh3atcEKf6362EaB3+kTUbCsVA==", - "requires": { - "@hapi/boom": "7.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/joi": "16.x.x" - } - }, - "@hapi/hoek": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.3.2.tgz", - "integrity": "sha512-NP5SG4bzix+EtSMtcudp8TvI0lB46mXNo8uFpTDw6tqxGx4z5yx+giIunEFA0Z7oUO4DuWrOJV9xqR2tJVEdyA==" + "@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "dev": true }, - "@hapi/iron": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-5.1.4.tgz", - "integrity": "sha512-+ElC+OCiwWLjlJBmm8ZEWjlfzTMQTdgPnU/TsoU5QsktspIWmWi9IU4kU83nH+X/SSya8TP8h8P11Wr5L7dkQQ==", + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "requires": { - "@hapi/b64": "4.x.x", - "@hapi/boom": "7.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/cryptiles": "4.x.x", - "@hapi/hoek": "8.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/joi": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-16.1.7.tgz", - "integrity": "sha512-anaIgnZhNooG3LJLrTFzgGALTiO97zRA1UkvQHm9KxxoSiIzCozB3RCNCpDnfhTJD72QlrHA8nwGmNgpFFCIeg==", + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "requires": { - "@hapi/address": "^2.1.2", - "@hapi/formula": "^1.2.0", - "@hapi/hoek": "^8.2.4", - "@hapi/pinpoint": "^1.0.2", - "@hapi/topo": "^3.1.3" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/mimos": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-4.1.1.tgz", - "integrity": "sha512-CXoi/zfcTWfKYX756eEea8rXJRIb9sR4d7VwyAH9d3BkDyNgAesZxvqIdm55npQc6S9mU3FExinMAQVlIkz0eA==", + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x", - "mime-db": "1.x.x" + "@babel/helper-plugin-utils": "^7.12.13" } }, - "@hapi/nigel": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-3.1.1.tgz", - "integrity": "sha512-R9YWx4S8yu0gcCBrMUDCiEFm1SQT895dMlYoeNBp8I6YhF1BFF1iYPueKA2Kkp9BvyHdjmvrxCOns7GMmpl+Fw==", + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x", - "@hapi/vise": "3.x.x" + "@babel/helper-plugin-utils": "^7.10.4" } }, - "@hapi/oppsy": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@hapi/oppsy/-/oppsy-2.1.2.tgz", - "integrity": "sha512-V/KNuFemyA//sowFFpeMRY4zE6szuy8vh6v2vWDPDhZFowOIwB7kqdFvmnBogk+aHHR+iKgKCU/SuUiv/xZyzg==", + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/pez": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-4.1.1.tgz", - "integrity": "sha512-TUa2C7Xk6J69HWrm+Ad+O6dFvdVAG0BiFUYaRsmkdWjFIfwHBCaOI1dWT/juNukSb39Lj6/mDVyjN+H4nKB3xg==", + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "requires": { - "@hapi/b64": "4.x.x", - "@hapi/boom": "7.x.x", - "@hapi/content": "4.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/nigel": "3.x.x" + "@babel/helper-plugin-utils": "^7.10.4" } }, - "@hapi/pinpoint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-1.0.2.tgz", - "integrity": "sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ==" - }, - "@hapi/podium": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-3.4.2.tgz", - "integrity": "sha512-g9zlAkRL2uDlnEo64xzEhFLblf4fdL5Z6evAO0wJhdxEvokI/+6ryv7k6uhND481LiLzQz8qTtPYMuhH1hichw==", + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x", - "@hapi/joi": "16.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/shot": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-4.1.2.tgz", - "integrity": "sha512-6LeHLjvsq/bQ0R+fhEyr7mqExRGguNTrxFZf5DyKe3CK6pNabiGgYO4JVFaRrLZ3JyuhkS0fo8iiRE2Ql2oA/A==", + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x", - "@hapi/joi": "16.x.x" + "@babel/helper-plugin-utils": "^7.10.4" } }, - "@hapi/somever": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-2.1.1.tgz", - "integrity": "sha512-cic5Sto4KGd9B0oQSdKTokju+rYhCbdpzbMb0EBnrH5Oc1z048hY8PaZ1lx2vBD7I/XIfTQVQetBH57fU51XRA==", + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, "requires": { - "@hapi/bounce": "1.x.x", - "@hapi/hoek": "8.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/statehood": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-6.1.2.tgz", - "integrity": "sha512-pYXw1x6npz/UfmtcpUhuMvdK5kuOGTKcJNfLqdNptzietK2UZH5RzNJSlv5bDHeSmordFM3kGItcuQWX2lj2nQ==", + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "requires": { - "@hapi/boom": "7.x.x", - "@hapi/bounce": "1.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/cryptiles": "4.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/iron": "5.x.x", - "@hapi/joi": "16.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/subtext": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-6.1.2.tgz", - "integrity": "sha512-G1kqD1E2QdxpvpL26WieIyo3z0qCa/sAGSa2TJI/PYPWCR9rL0rqFvhWY774xPZ4uK1PV3TIaJcx8AruAvxclg==", + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, "requires": { - "@hapi/boom": "7.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/content": "4.x.x", - "@hapi/file": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/pez": "4.x.x", - "@hapi/wreck": "15.x.x" + "@babel/helper-plugin-utils": "^7.8.0" } }, - "@hapi/teamwork": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-3.3.1.tgz", - "integrity": "sha512-61tiqWCYvMKP7fCTXy0M4VE6uNIwA0qvgFoiDubgfj7uqJ0fdHJFQNnVPGrxhLWlwz0uBPWrQlBH7r8y9vFITQ==" - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", - "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, "requires": { - "@hapi/hoek": "^8.3.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, - "@hapi/vise": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-3.1.1.tgz", - "integrity": "sha512-OXarbiCSadvtg+bSdVPqu31Z1JoBL+FwNYz3cYoBKQ5xq1/Cr4A3IkGpAZbAuxU5y4NL5pZFZG3d2a3ZGm/dOQ==", + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x" + "@babel/helper-plugin-utils": "^7.14.5" } }, - "@hapi/wreck": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-15.1.0.tgz", - "integrity": "sha512-tQczYRTTeYBmvhsek/D49En/5khcShaBEmzrAaDjMrFXKJRuF8xA8+tlq1ETLBFwGd6Do6g2OC74rt11kzawzg==", + "@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", "requires": { - "@hapi/boom": "7.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x" + "regenerator-runtime": "^0.13.4" } }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" } }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ms": "2.1.2" } + }, + "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 + }, + "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 } } }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" } }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, + "@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 + }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" } }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "@eslint/eslintrc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.2.tgz", + "integrity": "sha512-x1ZXdEFsvTcnbTZgqcWUL9w2ybgZCw/qbKTPQnab+XnYA2bMQpJCh+/bBzCRfDJaJdlrrQlOk49jNtru9gL/6Q==", "dev": true, "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.0.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "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 + }, + "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 + }, + "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 } } }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } + "@exodus/schemasafe": { + "version": "1.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.6.tgz", + "integrity": "sha512-dDnQizD94EdBwEj/fh3zPRa/HWCS9O5au2PuHhZBbuM3xWHxuaKzPBOEWze7Nn0xW68MIpZ7Xdyn1CoCpjKCuQ==" }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } + "@gar/promisify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", + "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", + "dev": true }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, + "@grpc/proto-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.2.tgz", + "integrity": "sha512-q2Qle60Ht2OQBCp9S5hv1JbI4uBBq6/mqSevFNK3ZEgRDBCAkWqZPUhD/K9gXOHrHKluliHiVq2L9sw1mVyAIg==", "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } } } }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, + "@hapi/accept": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.2.tgz", + "integrity": "sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==", "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" } }, - "@korzio/djv-draft-04": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@korzio/djv-draft-04/-/djv-draft-04-2.0.1.tgz", - "integrity": "sha512-MeTVcNsfCIYxK6T7jW1sroC7dBAb4IfLmQe6RoCqlxHN5NFkzNpgdnBPR+/0D2wJDUJHM9s9NQv+ouhxKjvUjg==", - "dev": true, - "optional": true - }, - "@mojaloop/central-services-error-handling": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-error-handling/-/central-services-error-handling-8.3.0.tgz", - "integrity": "sha512-2m/TyJ45AGJ+1hCobLiIj9idb1BGKGhq1LJ5n6nRlF6cJR7wx0+Y2cOlI2khl7VZ+PNdonHL9ODbRo7ZGqFczQ==", + "@hapi/ammo": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-5.0.1.tgz", + "integrity": "sha512-FbCNwcTbnQP4VYYhLNGZmA76xb2aHg9AMPiy18NZyWMG310P5KdFGyA9v2rm5ujrIny77dEEIkMOwl0Xv+fSSA==", "requires": { - "@mojaloop/sdk-standard-components": "8.1.4", - "lodash": "4.17.15" + "@hapi/hoek": "9.x.x" } }, - "@mojaloop/central-services-logger": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-8.1.2.tgz", - "integrity": "sha512-wNnr07xcJNAy+KX2C8Djb6ubeH2c1KkfXMyMJz+/dKrfqyVcqcI0RuhneERZrJMI5Ah4X9Sjcuz+LqH9HQoW/w==", + "@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", "requires": { - "winston": "3.2.1" + "@hapi/hoek": "9.x.x" } }, - "@mojaloop/central-services-shared": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-8.4.1.tgz", - "integrity": "sha512-3HBPiMz0mVwYPxtmcmCHFgpVs10EBCVMFW+f4SqxNbC52DSn9K74w2ryGbr4SDqK9t6QBmCayHSEJhfwNhozBg==", - "requires": { - "@hapi/catbox": "10.2.3", - "@hapi/catbox-memory": "4.1.1", - "@mojaloop/central-services-error-handling": "8.3.0", - "@mojaloop/central-services-logger": "8.1.2", - "@mojaloop/central-services-stream": "8.3.0", - "@mojaloop/event-sdk": "8.3.0", - "axios": "0.19.0", - "base64url": "3.0.1", - "clone": "2.1.2", - "data-urls": "1.1.0", - "glob": "7.1.5", - "immutable": "3.8.2", - "lodash": "4.17.15", - "mustache": "3.1.0", - "raw-body": "2.4.1" - }, - "dependencies": { - "glob": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", - "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "requires": { + "@hapi/hoek": "9.x.x" } }, - "@mojaloop/central-services-stream": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-stream/-/central-services-stream-8.3.0.tgz", - "integrity": "sha512-ztWmDWudH5b5T+n/MrIxbHa5hU63O1yk4WqUmzNwBdRG+HtD2Mlim6HzbQXXWSr722zgL1x7olirH7unhZGxaQ==", + "@hapi/bounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz", + "integrity": "sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A==", "requires": { - "@mojaloop/central-services-error-handling": "8.3.0", - "@mojaloop/central-services-logger": "8.1.2", - "async": "3.1.0", - "debug": "4.1.1", - "events": "3.0.0", - "node-rdkafka": "2.7.1", - "raw-body": "2.4.1" - }, - "dependencies": { - "async": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", - "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==" - } + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" } }, - "@mojaloop/event-sdk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-8.3.0.tgz", - "integrity": "sha512-Shc2NMZPHu8BKU9qPNxJVUhocr+l500DYZ2v+gxDjUL9PgmBCcFKsmGyf10PtV5xK9bLWxviWrhvXdZZyOQ6oQ==", + "@hapi/bourne": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", + "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==" + }, + "@hapi/call": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-8.0.1.tgz", + "integrity": "sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g==", "requires": { - "@grpc/proto-loader": "0.5.2", - "@mojaloop/central-services-logger": "8.1.2", - "@types/protobufjs": "6.0.0", - "brototype": "0.0.6", - "error-callsites": "2.0.2", - "grpc": "1.24.0", - "lodash": "4.17.15", - "moment": "2.24.0", - "parse-strings-in-object": "1.2.0", - "protobufjs": "6.8.8", - "rc": "1.2.8", - "serialize-error": "4.1.0", - "sinon": "7.5.0", - "traceparent": "1.0.0", - "uuid4": "1.1.4" + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" } }, - "@mojaloop/ml-number": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@mojaloop/ml-number/-/ml-number-8.2.0.tgz", - "integrity": "sha512-9g08YprQ/6MdI3SfW+EGJ2uQ7oWhXw7vxTo55BUoVzrOnZckXXuJy/jsZSADjUAyQtm/+Bcl9mrRaOGNeS8ayA==", + "@hapi/catbox": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", + "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", "requires": { - "bignumber.js": "9.0.0" - }, - "dependencies": { - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - } + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/podium": "4.x.x", + "@hapi/validate": "1.x.x" } }, - "@mojaloop/sdk-standard-components": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-8.1.4.tgz", - "integrity": "sha512-OyUYb3DenwZyUQdvdfpOqUHXlOaHCqedh12Y7RIXPUwanadL/AU+b5RWKm6HY1PrELhvTaBoyzOLRaCrAegx5Q==", + "@hapi/catbox-memory": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-5.0.1.tgz", + "integrity": "sha512-QWw9nOYJq5PlvChLWV8i6hQHJYfvdqiXdvTupJFh0eqLZ64Xir7mKNi96d5/ZMUAqXPursfNDIDxjFgoEDUqeQ==", "requires": { - "base64url": "^3.0.1", - "ilp-packet": "2.2.0", - "jsonwebtoken": "^8.5.1", - "jws": "^3.2.2", - "request": "^2.34", - "request-promise-native": "^1.0.7" + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" } }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "@hapi/content": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-5.0.2.tgz", + "integrity": "sha512-mre4dl1ygd4ZyOH3tiYBrOUBzV7Pu/EOs8VLGf58vtOEECWed8Uuw6B4iR9AN/8uQt42tB04qpVaMyoMQh0oMw==", "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@hapi/boom": "9.x.x" } }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + "@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "requires": { + "@hapi/boom": "9.x.x" + } }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + "@hapi/file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz", + "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ==" }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + "@hapi/good": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@hapi/good/-/good-9.0.1.tgz", + "integrity": "sha512-zHSjw+LieqDgu5pXLUHqUJTMSgBKIdKHwxmXNoh9qVz+kSPQH463ol6OEBSTVdy0yQawKVI4eAyeqown++TpbA==", + "requires": { + "@hapi/hoek": "9.x.x", + "@hapi/oppsy": "3.x.x", + "@hapi/validate": "1.x.x", + "pumpify": "2.x.x" + } }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + "@hapi/hapi": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.2.1.tgz", + "integrity": "sha512-OXAU+yWLwkMfPFic+KITo+XPp6Oxpgc9WUH+pxXWcTIuvWbgco5TC/jS8UDvz+NFF5IzRgF2CL6UV/KLdQYUSQ==", + "requires": { + "@hapi/accept": "^5.0.1", + "@hapi/ammo": "^5.0.1", + "@hapi/boom": "^9.1.0", + "@hapi/bounce": "^2.0.0", + "@hapi/call": "^8.0.0", + "@hapi/catbox": "^11.1.1", + "@hapi/catbox-memory": "^5.0.0", + "@hapi/heavy": "^7.0.1", + "@hapi/hoek": "^9.0.4", + "@hapi/mimos": "^6.0.0", + "@hapi/podium": "^4.1.1", + "@hapi/shot": "^5.0.5", + "@hapi/somever": "^3.0.0", + "@hapi/statehood": "^7.0.3", + "@hapi/subtext": "^7.0.3", + "@hapi/teamwork": "^5.1.0", + "@hapi/topo": "^5.0.0", + "@hapi/validate": "^1.1.1" + } }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + "@hapi/heavy": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-7.0.1.tgz", + "integrity": "sha512-vJ/vzRQ13MtRzz6Qd4zRHWS3FaUc/5uivV2TIuExGTM9Qk+7Zzqj0e2G7EpE6KztO9SalTbiIkTh7qFKj/33cA==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true + "@hapi/hoek": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" }, - "@sinonjs/commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", - "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "@hapi/inert": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@hapi/inert/-/inert-6.0.4.tgz", + "integrity": "sha512-tpmNqtCCAd+5Ts07bJmMaA79+ZUIf0zSWnQMaWtbcO4nGrO/yXB2AzoslfzFX2JEV9vGeF3FfL8mYw0pHl8VGg==", "requires": { - "type-detect": "4.0.8" + "@hapi/ammo": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bounce": "2.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x", + "lru-cache": "^6.0.0" } }, - "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" } }, - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "@hapi/mimos": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-6.0.0.tgz", + "integrity": "sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg==", "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" + "@hapi/hoek": "9.x.x", + "mime-db": "1.x.x" } }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, + "@hapi/nigel": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-4.0.2.tgz", + "integrity": "sha512-ht2KoEsDW22BxQOEkLEJaqfpoKPXxi7tvabXy7B/77eFtOyG5ZEstfZwxHQcqAiZhp58Ae5vkhEqI03kawkYNw==", "requires": { - "defer-to-connect": "^1.0.1" + "@hapi/hoek": "^9.0.4", + "@hapi/vise": "^4.0.0" } }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, + "@hapi/oppsy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/oppsy/-/oppsy-3.0.0.tgz", + "integrity": "sha512-0kfUEAqIi21GzFVK2snMO07znMEBiXb+/pOx1dmgOO9TuvFstcfmHU5i56aDfiFP2DM5WzQCU2UWc2gK1lMDhQ==", "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@hapi/hoek": "9.x.x" } }, - "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", - "dev": true, + "@hapi/pez": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-5.0.3.tgz", + "integrity": "sha512-mpikYRJjtrbJgdDHG/H9ySqYqwJ+QU/D7FXsYciS9P7NYBXE2ayKDAy3H0ou6CohOCaxPuTV4SZ0D936+VomHA==", "requires": { - "@babel/types": "^7.0.0" + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/content": "^5.0.2", + "@hapi/hoek": "9.x.x", + "@hapi/nigel": "4.x.x" } }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, + "@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" } }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, + "@hapi/shot": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-5.0.5.tgz", + "integrity": "sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A==", "requires": { - "@babel/types": "^7.3.0" + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, + "@hapi/somever": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-3.0.1.tgz", + "integrity": "sha512-4ZTSN3YAHtgpY/M4GOtHUXgi6uZtG9nEZfNI6QrArhK0XN/RDVgijlb9kOmXwCR5VclDSkBul9FBvhSuKXx9+w==", "requires": { - "@types/istanbul-lib-coverage": "*" + "@hapi/bounce": "2.x.x", + "@hapi/hoek": "9.x.x" } }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, + "@hapi/statehood": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-7.0.3.tgz", + "integrity": "sha512-pYB+pyCHkf2Amh67QAXz7e/DN9jcMplIL7Z6N8h0K+ZTy0b404JKPEYkbWHSnDtxLjJB/OtgElxocr2fMH4G7w==", "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" + "@hapi/boom": "9.x.x", + "@hapi/bounce": "2.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/iron": "6.x.x", + "@hapi/validate": "1.x.x" } }, - "@types/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", - "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" - }, - "@types/node": { - "version": "10.14.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.22.tgz", - "integrity": "sha512-9taxKC944BqoTVjE+UT3pQH0nHZlTvITwfsOZqyc+R3sfJuxaTtxWjfn1K2UlxyPcKHf0rnaXcVFrS9F9vf0bw==" - }, - "@types/protobufjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/protobufjs/-/protobufjs-6.0.0.tgz", - "integrity": "sha512-A27RDExpAf3rdDjIrHKiJK6x8kqqJ4CmoChwtipfhVAn1p7+wviQFFP7dppn8FslSbHtQeVPvi8wNKkDjSYjHw==", + "@hapi/subtext": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-7.0.3.tgz", + "integrity": "sha512-CekDizZkDGERJ01C0+TzHlKtqdXZxzSWTOaH6THBrbOHnsr3GY+yiMZC+AfNCypfE17RaIakGIAbpL2Tk1z2+A==", "requires": { - "protobufjs": "*" + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/content": "^5.0.2", + "@hapi/file": "2.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/pez": "^5.0.1", + "@hapi/wreck": "17.x.x" } }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true + "@hapi/teamwork": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.0.tgz", + "integrity": "sha512-llqoQTrAJDTXxG3c4Kz/uzhBS1TsmSBa/XG5SPcVXgmffHE1nFtyLIK0hNJHCB3EuBKT84adzd1hZNY9GJLWtg==" }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "dev": true, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "requires": { - "@types/yargs-parser": "*" + "@hapi/hoek": "^9.0.0" } }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true + "@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, + "@hapi/vise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", + "integrity": "sha512-eYyLkuUiFZTer59h+SGy7hUm+qE9p+UemePTHLlIWppEd+wExn3Df5jO04bFQTm7nleF5V8CtuYQYb+VFpZ6Sg==", "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "@hapi/hoek": "9.x.x" } }, - "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==" + "@hapi/vision": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@hapi/vision/-/vision-6.1.0.tgz", + "integrity": "sha512-ll0zJ13xDxCYIWvC1aq/8srK0bTXfqZYGT+YoTi/fS42gYYJ3dnvmS35r8T8XXtJ6F6cmya8G2cRlMR/z11LQw==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bounce": "2.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } }, - "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", - "dev": true + "@hapi/wreck": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.1.0.tgz", + "integrity": "sha512-nx6sFyfqOpJ+EFrHX+XWwJAxs3ju4iHdbB/bwR8yTNZOiYmuhA8eCe7lYPtYmb4j7vyK/SlbaQsmTtUrMvPEBw==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/hoek": "9.x.x" + } }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", "dev": true, "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" }, "dependencies": { - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 } } }, - "acorn-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", - "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", "dev": true }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "requires": { - "es6-promisify": "^5.0.0" + "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" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, - "agentkeepalive": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", - "dev": true, - "requires": { - "humanize-ms": "^1.2.1" - } + "@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 }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "@jest/console": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.5.tgz", + "integrity": "sha512-smtlRF9vNKorRMCUtJ+yllIoiY8oFmfFG7xlzsAE76nKEwXNhjPOJIsc7Dv+AUitVt76t+KjIpUP9m98Crn2LQ==", + "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.2.5", + "jest-util": "^27.2.5", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "ansi-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", - "dev": true, - "requires": { - "string-width": "^3.0.0" + "@jest/core": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.5.tgz", + "integrity": "sha512-VR7mQ+jykHN4WO3OvusRJMk4xCa2MFLipMS+43fpcRGaYrN1KwMATfVEXif7ccgFKYGy5D1TVXTNE4mGq/KMMA==", + "dev": true, + "requires": { + "@jest/console": "^27.2.5", + "@jest/reporters": "^27.2.5", + "@jest/test-result": "^27.2.5", + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.2.5", + "jest-config": "^27.2.5", + "jest-haste-map": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.5", + "jest-resolve-dependencies": "^27.2.5", + "jest-runner": "^27.2.5", + "jest-runtime": "^27.2.5", + "jest-snapshot": "^27.2.5", + "jest-util": "^27.2.5", + "jest-validate": "^27.2.5", + "jest-watcher": "^27.2.5", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "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==", + "@jest/environment": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.5.tgz", + "integrity": "sha512-XvUW3q6OUF+54SYFCgbbfCd/BKTwm5b2MGLoc2jINXQLKQDTCS2P2IrpPOtQ08WWZDGzbhAzVhOYta3J2arubg==", + "dev": true, "requires": { - "color-convert": "^1.9.0" + "@jest/fake-timers": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.2.5" } }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "@jest/fake-timers": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.5.tgz", + "integrity": "sha512-ZGUb6jg7BgwY+nmO0TW10bc7z7Hl2G/UTAvmxEyZ/GgNFoa31tY9/cgXmqcxnnZ7o5Xs7RAOz3G1SKIj8IVDlg==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "@jest/types": "^27.2.5", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.2.5", + "jest-mock": "^27.2.5", + "jest-util": "^27.2.5" + }, + "dependencies": { + "@sinonjs/fake-timers": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "@jest/globals": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.5.tgz", + "integrity": "sha512-naRI537GM+enFVJQs6DcwGYPn/0vgJNb06zGVbzXfDfe/epDPV73hP1vqO37PqSKDeOXM2KInr6ymYbL1HTP7g==", + "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "@jest/environment": "^27.2.5", + "@jest/types": "^27.2.5", + "expect": "^27.2.5" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + "@jest/reporters": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.5.tgz", + "integrity": "sha512-zYuR9fap3Q3mxQ454VWF8I6jYHErh368NwcKHWO2uy2fwByqBzRHkf9j2ekMDM7PaSTWcLBSZyd7NNxR1iHxzQ==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.2.5", + "@jest/test-result": "^27.2.5", + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.2.5", + "jest-resolve": "^27.2.5", + "jest-util": "^27.2.5", + "jest-worker": "^27.2.5", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "ascli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", - "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "@jest/test-result": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.5.tgz", + "integrity": "sha512-ub7j3BrddxZ0BdSnM5JCF6cRZJ/7j3wgdX0+Dtwhw2Po+HKsELCiXUTvh+mgS4/89mpnU1CPhZxe2mTvuLPJJg==", + "dev": true, "requires": { - "colour": "~0.7.1", - "optjs": "~3.2.2" + "@jest/console": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "@jest/test-sequencer": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.5.tgz", + "integrity": "sha512-8j8fHZRfnjbbdMitMAGFKaBZ6YqvFRFJlMJzcy3v75edTOqc7RY65S9JpMY6wT260zAcL2sTQRga/P4PglCu3Q==", + "dev": true, "requires": { - "safer-buffer": "~2.1.0" + "@jest/test-result": "^27.2.5", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.5", + "jest-runtime": "^27.2.5" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "@jest/transform": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.5.tgz", + "integrity": "sha512-29lRtAHHYGALbZOx343v0zKmdOg4Sb0rsA1uSv0818bvwRhs3TyElOmTVXlrw0v1ZTqXJCAH/cmoDXimBhQOJQ==", + "dev": true, "requires": { - "lodash": "^4.17.14" + "@babel/core": "^7.1.0", + "@jest/types": "^27.2.5", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.2.5", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "audit-resolve-core": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.7.tgz", - "integrity": "sha512-9nLm9SgyMbMv86X5a/E6spcu3V+suceHF6Pg4BwjPqfxWBKDvISagJH9Ji592KihqBev4guKFO3BiNEVNnqh3A==", + "@jest/types": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", "dev": true, "requires": { - "concat-stream": "^1.6.2", - "debug": "^4.1.1", - "djv": "^2.1.2", - "spawn-shell": "^2.1.0", - "yargs-parser": "^10.1.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "has-flag": "^4.0.0" } } } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + "@korzio/djv-draft-04": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@korzio/djv-draft-04/-/djv-draft-04-2.0.1.tgz", + "integrity": "sha512-MeTVcNsfCIYxK6T7jW1sroC7dBAb4IfLmQe6RoCqlxHN5NFkzNpgdnBPR+/0D2wJDUJHM9s9NQv+ouhxKjvUjg==", + "dev": true, + "optional": true }, - "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "@mapbox/node-pre-gyp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", + "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.1", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, + "@mojaloop/central-services-error-handling": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-error-handling/-/central-services-error-handling-11.3.0.tgz", + "integrity": "sha512-Ctl3ad8Uc2kpquIq+nc90s+CdXoHlrWscoBCRe7/VOxLlIi+kRgXWtJ/UWD3dJs8t0f8/69KCN9Qgve4lEyuqA==", "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" + "@mojaloop/sdk-standard-components": "15.9.0", + "lodash": "4.17.21" + }, + "dependencies": { + "@mojaloop/sdk-standard-components": { + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-15.9.0.tgz", + "integrity": "sha512-ORELbkNuzPS2ISZniQcvSDM4/UXQDoGh+9/9AWPkeYbLA1gc9uTfiLOiur0NyzGXKKkLbJbQntstmK3mlfF3RQ==", + "requires": { + "base64url": "3.0.1", + "fast-safe-stringify": "^2.0.7", + "ilp-packet": "2.2.0", + "jsonwebtoken": "8.5.1", + "jws": "4.0.0" + } + } } }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, + "@mojaloop/central-services-logger": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-10.6.2.tgz", + "integrity": "sha512-xo6L25jG3+FcOWFHSp0fVnpxMIpIFtsxA3Rr253uB/E/3616aHj1iKaeXBc64RpMDdEG/vsWP9Wuo3kXq39GpQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" + "@types/node": "^16.10.1", + "parse-strings-in-object": "2.0.0", + "rc": "1.2.8", + "winston": "3.3.3" } }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, + "@mojaloop/central-services-metrics": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-metrics/-/central-services-metrics-11.0.0.tgz", + "integrity": "sha512-NcSJSbCpa5hvMR17x1HeQUyY6DjU31/a7HmYXFDb0Afxl1Z3P+9xllVZGyQpt5e7HCmxxzytoeylSAhwyJsRfQ==", "requires": { - "@types/babel__traverse": "^7.0.6" + "prom-client": "13.1.0" } }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, + "@mojaloop/central-services-shared": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-14.0.0.tgz", + "integrity": "sha512-b6kDvOV/alhRbsytbTV6lGq7c/1gaRTg1ovmZPlue1oa3IVym05Juy7OTcPMqMjFhSMkxhoHF2TVNANTr4Q5Xw==", "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" + "@hapi/catbox": "11.1.1", + "@hapi/catbox-memory": "5.0.1", + "axios": "0.21.4", + "clone": "2.1.2", + "dotenv": "10.0.0", + "env-var": "7.0.1", + "event-stream": "4.0.1", + "immutable": "3.8.2", + "lodash": "4.17.21", + "mustache": "4.2.0", + "openapi-backend": "4.2.0", + "raw-body": "2.4.1", + "rc": "1.2.8", + "shins": "2.6.0", + "uuid4": "2.0.2", + "widdershins": "4.0.1", + "yaml": "1.10.2" + }, + "dependencies": { + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + } } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "@mojaloop/event-sdk": { + "version": "10.7.1", + "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-10.7.1.tgz", + "integrity": "sha512-XbBY5dCh1vOvGnzM9AUxynG89JtF0PMvc+HJsggm2qCE7F+KzIOTi0/8rns0y3l9mgw5L8sGsZbYdYObijzBEg==", "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "@grpc/proto-loader": "0.6.2", + "@mojaloop/central-services-logger": "10.6.1", + "brototype": "0.0.6", + "error-callsites": "2.0.3", + "grpc": "1.24.9", + "lodash": "4.17.21", + "moment": "2.29.1", + "parse-strings-in-object": "2.0.0", + "protobufjs": "6.11.2", + "rc": "1.2.8", + "serialize-error": "8.1.0", + "sinon": "10.0.0", + "traceparent": "1.0.0", + "tslib": "2.2.0", + "uuid4": "2.0.2", + "winston": "3.3.3" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "@mojaloop/central-services-logger": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-10.6.1.tgz", + "integrity": "sha512-Ya40L2lsPFFVHEkkjl5sle2DHQ3fqUNMqGw7SSqhkB21l13EY78b4zCHiWDMzVI3S+xZ3QQzyGdlfl7H3ABfEg==", "requires": { - "is-descriptor": "^1.0.0" + "parse-strings-in-object": "2.0.0", + "rc": "1.2.8", + "winston": "3.3.3" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "sinon": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-10.0.0.tgz", + "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", "requires": { - "kind-of": "^6.0.0" + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/samsam": "^5.3.1", + "diff": "^4.0.2", + "nise": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "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==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "has-flag": "^4.0.0" } + }, + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" } } }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + "@mojaloop/ml-number": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@mojaloop/ml-number/-/ml-number-11.2.1.tgz", + "integrity": "sha512-d/DHZIOswfypnhzVEFyl0u1jWJxw1f2FbHk+uxp1CY7laep44X/KGzcTFp//5EEzZnuAdjzbyj6I9QLgkjBfuw==", + "requires": { + "bignumber.js": "9.0.1" + }, + "dependencies": { + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + } + } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "@mojaloop/sdk-standard-components": { + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-15.13.0.tgz", + "integrity": "sha512-KzPP6aqM+Z2Kd0j7jvarPdeNfQnClQw7Uw611l7olUPKMzE78z6S/0HbC/Yt9EGbkTl20Xe46hxD1MJKzBB8pg==", "requires": { - "tweetnacl": "^0.14.3" + "base64url": "3.0.1", + "fast-safe-stringify": "^2.0.7", + "ilp-packet": "2.2.0", + "jsonwebtoken": "8.5.1", + "jws": "4.0.0" } }, - "bignumber.js": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-5.0.0.tgz", - "integrity": "sha512-KWTu6ZMVk9sxlDJQh2YH1UOnfDP8O8TpxUxgQG/vKASoSnEjK9aVuOueFaPcQEYQ5fyNXNTOYwYw3099RYebWg==" + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "requires": { - "file-uri-to-path": "1.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" } }, - "blipp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/blipp/-/blipp-4.0.1.tgz", - "integrity": "sha512-nmtErzngVgJF6HlpnEymOil23m5U82oTYhbU8m619kQzj8yJ2q1ZFbL45i+dBcO92XTocyyj3QtC3GMxRujv8w==", + "@npmcli/fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.0.0.tgz", + "integrity": "sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==", + "dev": true, "requires": { - "@hapi/hoek": "8.x.x", - "@hapi/joi": "15.x.x", - "chalk": "2.x.x", - "easy-table": "1.x.x" + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" }, "dependencies": { - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" + "lru-cache": "^6.0.0" } } } }, - "bluebird": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", - "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==" - }, - "boxen": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", - "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "@npmcli/git": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", "dev": true, "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^2.4.2", - "cli-boxes": "^2.2.0", - "string-width": "^3.0.0", - "term-size": "^1.2.0", - "type-fest": "^0.3.0", - "widest-line": "^2.0.0" + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "lru-cache": "^6.0.0" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "isexe": "^2.0.0" } } } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" } }, - "brackets2dots": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brackets2dots/-/brackets2dots-1.1.0.tgz", - "integrity": "sha1-Pz1AN1/GYM4P0AT6J9Z7NPlGmsM=" - }, - "brototype": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/brototype/-/brototype-0.0.6.tgz", - "integrity": "sha1-mz8HNkeDOXuPHEvuehQZk1ZuS0Q=" - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "@npmcli/node-gyp": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", "dev": true }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", "dev": true, "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } + "infer-owner": "^1.0.4" } }, - "bser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", - "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", + "@npmcli/run-script": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", + "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", "dev": true, "requires": { - "node-int64": "^0.4.0" + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" } }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, - "bytebuffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", - "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "requires": { - "long": "~3" - } + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, - "cacache": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", - "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", - "dev": true, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - }, - "dependencies": { - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - } + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "http-cache-semantics": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", - "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", - "dev": true - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, + "@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", "requires": { - "rsvp": "^4.8.4" + "@hapi/hoek": "^9.0.0" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, - "chance": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.3.tgz", - "integrity": "sha512-XeJsdoVAzDb1WRPRuMBesRSiWpW1uNTo5Fd7mYxPJsAfgX71+jfuCOHOdbyBz2uAUZ8TwKcXgWk3DMedFfJkbg==", + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", "dev": true }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "requires": { + "type-detect": "4.0.8" + } }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", - "dev": true + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } }, - "cint": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/cint/-/cint-8.2.1.tgz", - "integrity": "sha1-cDhrG0jidz0NYxZqVa/5TvRFahI=", - "dev": true + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } + "defer-to-connect": "^1.0.1" } }, - "cli-boxes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", - "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "@types/babel__core": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", "dev": true, "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - } + "@babel/types": "^7.0.0" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "@types/bytebuffer": { + "version": "5.0.42", + "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.42.tgz", + "integrity": "sha512-lEgKojWUAc/MG2t649oZS5AfYFP2xRNPoDuwDBlBMjHXd8MaGPgFgtCXUK7inZdBOygmVf10qxc1Us8GXC96aw==", + "requires": { + "@types/long": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "requires": { - "mimic-response": "^1.0.0" + "@types/node": "*" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "@types/istanbul-lib-coverage": "*" } }, - "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "@types/istanbul-lib-report": "*" } }, - "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==", + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/node": { + "version": "16.10.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.8.tgz", + "integrity": "sha512-atlRPM4gM/BABQ2MiXm38veMVL+kz6vFAj1hvqC1wDxWNrnr3t58PozLSecgLBrKNGISunQl2SxxIJcYV3tO2w==" + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, "requires": { - "color-name": "1.1.3" + "@types/yargs-parser": "*" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, - "colorette": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz", - "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==" + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true }, - "colornames": { + "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" } }, - "colour": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", - "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", + "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, - "configstore": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", - "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "agentkeepalive": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", + "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", "dev": true, "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" }, "dependencies": { - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "pify": "^3.0.0" + "ms": "2.1.2" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" } }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } }, - "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" + "ajv-keywords": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.0.0.tgz", + "integrity": "sha512-ULd1QMjRoH6JDNUQIfDLrlE+OgZlFaxyYCjzt58uNuUQtKXt8/U+vK/8Ql0gyn/C5mqZzUWtKMqr/4YquvTrWA==", + "requires": { + "fast-deep-equal": "^3.1.3" + } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "string-width": "^4.1.0" } }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "cssom": "0.3.x" + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } } }, - "curriable": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/curriable/-/curriable-1.3.0.tgz", - "integrity": "sha512-7kfjDPRSF+pguU0TlfSFBMCd8XlmF29ZAiXcq/zaN4LhZvWdvV0Y72AvaWFqInXZG9Yg1kA1UMkpE9lFBKMpQA==" - }, - "curry2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/curry2/-/curry2-1.0.3.tgz", - "integrity": "sha1-OBkdVfEGC/6kfKCACThbuHj2YS8=", - "requires": { - "fast-bind": "^1.0.0" - } + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "requires": { - "assert-plus": "^1.0.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "default-require-extensions": "^3.0.0" } }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { - "mimic-response": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "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 }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } }, - "default-shell": { + "array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, + "arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/default-shell/-/default-shell-1.0.1.tgz", - "integrity": "sha1-dSMEvdxhdPSespy5iP7qC4gTyLw=", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "optional": true, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", "requires": { - "clone": "^1.0.2" - }, - "dependencies": { - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "optional": true - } + "colour": "~0.7.1", + "optjs": "~3.2.2" } }, - "defer-to-connect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.0.tgz", - "integrity": "sha512-WE2sZoctWm/v4smfCAdjYbrfS55JiMRdlY9ZubFhsYbteCK9+BvAx4YV7nPjYM6ZnX5BcoVKwfmyx9sIFTgQMQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "safer-buffer": "~2.1.0" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", + "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "audit-resolve-core": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.8.tgz", + "integrity": "sha512-F3IWaxu1Xw4OokmtG9hkmsKoJt8DQS7RZvot52zXHsANKvzFRMKVNTP1DAz1ztlRGmJx1XV16PcE+6m35bYoTA==", + "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "concat-stream": "^1.6.2", + "debug": "^4.1.1", + "djv": "^2.1.2", + "spawn-shell": "^2.1.0", + "yargs-parser": "^18.1.3" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, "requires": { - "kind-of": "^6.0.0" + "ms": "2.1.2" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "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 + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, - "deglob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-4.0.1.tgz", - "integrity": "sha512-/g+RDZ7yf2HvoW+E5Cy+K94YhgcFgr6C8LuHZD1O5HoNPkf3KY6RfXJ0DBGlB/NkLi5gml+G9zqRzk9S0mHZCg==", - "dev": true, - "requires": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^5.0.0", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" - }, - "dependencies": { - "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, - "diagnostics": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "axios": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.23.0.tgz", + "integrity": "sha512-NmvAE4i0YAv5cKq8zlDoPd1VLKAqX5oLuZKs8xkJa4qi6RGn0uhCYFjWtHHC9EM/MwOwYWOs53W+V0aqEXq1sg==", "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" + "follow-redirects": "^1.14.4" } }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true + "babel-jest": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.5.tgz", + "integrity": "sha512-GC9pWCcitBhSuF7H3zl0mftoKizlswaF0E3qi+rPL417wKkCB0d+Sjjb0OfXvxj7gWiBf497ldgRMii68Xz+2g==", + "dev": true, + "requires": { + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, - "djv": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/djv/-/djv-2.1.2.tgz", - "integrity": "sha512-ltQSINn+7aMTp7pKeQpfZg2ACd/Gy6VrL3LYuT25/plwPBb7xlGOekr463Luqn816AWJLuP7KZQGFct2JICyeA==", + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", "dev": true, "requires": { - "@korzio/djv-draft-04": "^2.0.1" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "babel-plugin-jest-hoist": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "requires": { - "esutils": "^2.0.2" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" } }, - "domexception": { + "babel-preset-current-node-syntax": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { - "webidl-conversions": "^4.0.2" + "@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" } }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "babel-preset-jest": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", + "dev": true, "requires": { - "is-obj": "^1.0.0" + "babel-plugin-jest-hoist": "^27.2.0", + "babel-preset-current-node-syntax": "^1.0.0" } }, - "dotsplit.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dotsplit.js/-/dotsplit.js-1.1.0.tgz", - "integrity": "sha1-JaI56r6SKpH/pdKhctbJ+4JFHgI=" + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "drange": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", - "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", - "dev": true + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true + "bath-es5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bath-es5/-/bath-es5-3.0.3.tgz", + "integrity": "sha512-PdCioDToH3t84lP40kUFCKWCOCH389Dl1kbC8FGoqOwamxsmqxxnJSXdkTOsPoNHXjem4+sJ+bbNoQm5zeCqxg==" }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "tweetnacl": "^0.14.3" } }, - "easy-table": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.1.tgz", - "integrity": "sha512-C9Lvm0WFcn2RgxbMnTbXZenMIWcBtkzMr+dWqq/JsVoGFSVUVlPqeOa5LP5kM0I3zoOazFpckOEb2/0LDFfToQ==", + "better-ajv-errors": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-0.6.7.tgz", + "integrity": "sha512-PYgt/sCzR4aGpyNy5+ViSQ77ognMnWq7745zM+/flYO4/Yisdtp9wDQW2IKCyVYPUxQt3E/b5GBSwfhd1LPdlg==", "requires": { - "ansi-regex": "^3.0.0", - "wcwidth": ">=1.0.1" + "@babel/code-frame": "^7.0.0", + "@babel/runtime": "^7.0.0", + "chalk": "^2.4.1", + "core-js": "^3.2.1", + "json-to-ast": "^2.0.3", + "jsonpointer": "^4.0.1", + "leven": "^3.1.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "bignumber.js": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-5.0.0.tgz", + "integrity": "sha512-KWTu6ZMVk9sxlDJQh2YH1UOnfDP8O8TpxUxgQG/vKASoSnEjK9aVuOueFaPcQEYQ5fyNXNTOYwYw3099RYebWg==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, + "blipp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/blipp/-/blipp-4.0.2.tgz", + "integrity": "sha512-QA5amT0IFJgCFgJeWw2udD2zZLui60NgqXTyvbSq+qpVbS6jfqELTRlC8PWW0yD4+chdZ2a+svnN6WE9zqfK5Q==", "requires": { - "safe-buffer": "^5.0.1" + "@hapi/hoek": "9.x.x", + "chalk": "4.x.x", + "easy-table": "1.x.x", + "joi": "17.x.x" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "enabled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", - "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { - "env-variable": "0.0.x" + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + } } }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "dev": true, "requires": { - "iconv-lite": "~0.4.13" + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "once": "^1.4.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "enjoi": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/enjoi/-/enjoi-4.1.1.tgz", - "integrity": "sha512-JTM4zGxiH0SqOZeRm4HcrdGgJN/4vJVNfJWchRbecFbH69S2uka2na5FfnTnwoad3BDRFwEVS5PJO+GtoWMG0A==", + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { - "hoek": "^5.0.4" - }, - "dependencies": { - "hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==" - } + "fill-range": "^7.0.1" } }, - "env-variable": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", - "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" + "brototype": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/brototype/-/brototype-0.0.6.tgz", + "integrity": "sha1-mz8HNkeDOXuPHEvuehQZk1ZuS0Q=" }, - "err-code": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "error-callsites": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/error-callsites/-/error-callsites-2.0.2.tgz", - "integrity": "sha512-s35ELWAKAY9oPqnnfP1V4AnasWV0r2ihaLlpsCGrykZgcR/YKsMXV3q8Ap4Mmp8U90VxJqxKJE5Io0IkkRhJIg==" - }, - "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==", + "browserslist": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", + "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "caniuse-lite": "^1.0.30001265", + "electron-to-chromium": "^1.3.867", + "escalade": "^3.1.1", + "node-releases": "^2.0.0", + "picocolors": "^1.0.0" }, "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true } } }, - "es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" + "node-int64": "^0.4.0" } }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "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 }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", "requires": { - "es6-promise": "^4.0.3" + "long": "~3" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - } + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" } }, - "eslint": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz", - "integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==", + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" }, "dependencies": { - "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { - "type-fest": "^0.5.2" + "pump": "^3.0.0" } }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "caniuse-lite": { + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chance": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.8.tgz", + "integrity": "sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg==", + "dev": true + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "requires": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + } + }, + "cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "requires": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cint": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/cint/-/cint-8.2.1.tgz", + "integrity": "sha1-cDhrG0jidz0NYxZqVa/5TvRFahI=", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-table": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", + "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-error-fragment": { + "version": "0.0.230", + "resolved": "https://registry.npmjs.org/code-error-fragment/-/code-error-fragment-0.0.230.tgz", + "integrity": "sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", + "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "conventional-changelog": { + "version": "3.1.24", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.24.tgz", + "integrity": "sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg==", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-atom": "^2.0.8", + "conventional-changelog-codemirror": "^2.0.8", + "conventional-changelog-conventionalcommits": "^4.5.0", + "conventional-changelog-core": "^4.2.1", + "conventional-changelog-ember": "^2.0.9", + "conventional-changelog-eslint": "^3.0.9", + "conventional-changelog-express": "^2.0.6", + "conventional-changelog-jquery": "^3.0.11", + "conventional-changelog-jshint": "^2.0.9", + "conventional-changelog-preset-loader": "^2.3.4" + } + }, + "conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-atom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", + "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-codemirror": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", + "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-config-spec": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz", + "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==", + "dev": true + }, + "conventional-changelog-conventionalcommits": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", + "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", + "dev": true, + "requires": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "conventional-changelog-ember": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", + "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-eslint": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", + "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-express": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", + "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-jquery": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", + "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", + "dev": true, + "requires": { + "q": "^1.5.1" + } + }, + "conventional-changelog-jshint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", + "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "dev": true + }, + "conventional-changelog-writer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", + "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", + "dev": true, + "requires": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.2.tgz", + "integrity": "sha512-Jr9KAKgqAkwXMRHjxDwO/zOCDKod1XdAESHAGuJX38iZ7ZzVti/tvVoysO0suMsdAObp9NQ2rHSsSbnAqZ5f5g==", + "dev": true, + "requires": { + "JSONStream": "^1.0.4", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "conventional-recommended-bump": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", + "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "dev": true, + "requires": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.7", + "conventional-commits-parser": "^3.2.0", + "git-raw-commits": "^2.0.8", + "git-semver-tags": "^4.1.1", + "meow": "^8.0.0", + "q": "^1.5.1" + }, + "dependencies": { + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + } + } + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-js": { + "version": "3.18.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz", + "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + } + }, + "css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "curriable": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/curriable/-/curriable-1.3.0.tgz", + "integrity": "sha512-7kfjDPRSF+pguU0TlfSFBMCd8XlmF29ZAiXcq/zaN4LhZvWdvV0Y72AvaWFqInXZG9Yg1kA1UMkpE9lFBKMpQA==" + }, + "dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } + } + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + } + }, + "default-shell": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/default-shell/-/default-shell-1.0.1.tgz", + "integrity": "sha1-dSMEvdxhdPSespy5iP7qC4gTyLw=", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "optional": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "optional": true + } + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "djv": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/djv/-/djv-2.1.4.tgz", + "integrity": "sha512-giDn+BVbtLlwtkvtcsZjbjzpALHB77skiv3FIu6Wp8b5j8BunDcVJYH0cGUaexp6s0Sb7IkquXXjsLBJhXwQpA==", + "dev": true, + "requires": { + "@korzio/djv-draft-04": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "domhandler": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", + "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dot": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dot/-/dot-1.1.3.tgz", + "integrity": "sha512-/nt74Rm+PcfnirXGEdhZleTwGC2LMnuKTeeTIlI82xb5loBBoXNYzr2ezCroPSMtilK8EZIfcNZwOcHN+ib1Lg==" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + } + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dotgitignore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz", + "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "minimatch": "^3.0.4" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "dev": true + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "requires": { + "ansi-regex": "^5.0.1", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" + }, + "electron-to-chromium": { + "version": "1.3.867", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.867.tgz", + "integrity": "sha512-WbTXOv7hsLhjJyl7jBfDkioaY++iVVZomZ4dU6TMe/SzucV6mUAs2VZn/AehBwuZMiNEQDaPuTGn22YK5o+aDw==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "env-var": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.0.1.tgz", + "integrity": "sha512-w4iTR5nongmpSgIByBhEaMvuLZOQCyzv4IUbhZnYMSKo/X8tj9E2Wdn4ikzKNFi29K78e5eT64iQkpar+nIYzw==" + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "error-callsites": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/error-callsites/-/error-callsites-2.0.3.tgz", + "integrity": "sha512-v036z4IEffZFE5kBkV5/F2MzhLnG0vuDyN+VXpzCf4yWXvX/1WJCI0A+TGTr8HWzBfCw5k8gr9rwAo09V+obTA==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + } + } + }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "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, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "restore-cursor": "^3.1.0" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, - "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==", + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, - "figures": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", - "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "prelude-ls": "~1.1.2" } - }, - "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + } + } + }, + "eslint": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.0.0.tgz", + "integrity": "sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.0.2", + "@humanwhocodes/config-array": "^0.6.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "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==", + "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 }, - "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 + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "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 }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "mimic-fn": "^2.1.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "ms": "2.1.2" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "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 }, - "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" + "shebang-regex": "^3.0.0" } }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "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 }, - "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, "eslint-config-standard": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz", - "integrity": "sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==" + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", + "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==" }, "eslint-config-standard-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-8.1.0.tgz", - "integrity": "sha512-ULVC8qH8qCqbU792ZOO6DaiaZyHNS/5CZt3hKqHkEhVlhPEPN3nfBqqxJCyp59XrjIBZPu1chMYe9T2DXZ7TMw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", + "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", "dev": true }, "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" + "debug": "^3.2.7", + "resolve": "^1.20.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.0.tgz", + "integrity": "sha512-hqSE88MmHl3ru9SYvDyGrlo0JwROlf9fiEMplEV7j/EAuq9iSlIlyCFbBT6pdULQBSnBYtYKiMLps+hKkyP7Gg==", "dev": true, "requires": { - "debug": "^2.6.8", + "debug": "^3.2.7", + "find-up": "^2.1.0", "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "find-up": { @@ -2884,12 +4876,6 @@ "path-exists": "^3.0.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -2914,6 +4900,12 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -2926,59 +4918,62 @@ } }, "eslint-plugin-es": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", - "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "requires": { - "eslint-utils": "^1.4.2", + "eslint-utils": "^2.0.0", "regexpp": "^3.0.0" }, "dependencies": { - "regexpp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", - "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } } }, "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", "dev": true, "requires": { - "array-includes": "^3.0.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", "has": "^1.0.3", + "is-core-module": "^2.6.0", "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" } }, "find-up": { @@ -2990,18 +4985,6 @@ "locate-path": "^2.0.0" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -3009,104 +4992,74 @@ "dev": true, "requires": { "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "path-exists": "^3.0.0" + } }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "p-try": "^1.0.0" } }, - "read-pkg-up": { + "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "p-limit": "^1.1.0" } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true } } }, "eslint-plugin-node": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", - "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "requires": { - "eslint-plugin-es": "^2.0.0", - "eslint-utils": "^1.4.2", + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", "ignore": "^5.1.1", "minimatch": "^3.0.4", "resolve": "^1.10.1", "semver": "^6.1.0" }, "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, "semver": { @@ -3118,26 +5071,30 @@ } }, "eslint-plugin-promise": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", - "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz", + "integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==", "dev": true }, "eslint-plugin-react": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", - "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.3.tgz", + "integrity": "sha512-ZMbFvZ1WAYSZKY662MBVEWR45VaBT6KSJCiupjrNlcdakB90juaZeDCbJq19e73JZQubqFtgETohwgAt8u5P6w==", "dev": true, "requires": { - "array-includes": "^3.0.3", + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.1.0", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.0", - "object.values": "^1.1.0", + "estraverse": "^5.2.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", "prop-types": "^15.7.2", - "resolve": "^1.10.1" + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" }, "dependencies": { "doctrine": { @@ -3148,100 +5105,132 @@ "requires": { "esutils": "^2.0.2" } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } } } }, - "eslint-plugin-standard": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", - "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", - "dev": true - }, "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", + "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", "dev": true }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, "espree": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", - "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz", + "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==", "dev": true, "requires": { - "acorn": "^7.1.0", - "acorn-jsx": "^5.1.0", - "eslint-visitor-keys": "^1.1.0" + "acorn": "^8.5.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.0.0" } }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "estraverse": "^5.1.0" } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true + "event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "requires": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -3250,6 +5239,13 @@ "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" + }, + "dependencies": { + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + } } }, "exit": { @@ -3258,871 +5254,552 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "expect": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.5.tgz", + "integrity": "sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA==", + "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-regex-util": "^27.0.6" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "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 } } }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extensible-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/extensible-error/-/extensible-error-1.0.2.tgz", "integrity": "sha512-kXU1FiTsGT8PyMKtFM074RK/VBpzwuQJicAHqBpsPDeTXBQiSALPjkjKXlyKdG/GP6lR7bBaEkq8qdoO2geu9g==" }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-bind/-/fast-bind-1.0.0.tgz", - "integrity": "sha1-f6llLLMyX1zR4lLWy08WDeGnbnU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "requires": { + "@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" + } }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "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==" }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "fast-stringify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-stringify/-/fast-stringify-1.1.2.tgz", - "integrity": "sha512-SfslXjiH8km0WnRiuPfpUKwlZjW5I878qsOm+2x8x3TgqmElOOLh1rgJFb+PolNdNRK3r8urEefqx0wt7vx1dA==" - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "figgy-pudding": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } + "fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, - "fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "reusify": "^1.0.4" } }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "requires": { - "locate-path": "^3.0.0" - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "bser": "2.1.1" } }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, + "fetch-blob": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.2.tgz", + "integrity": "sha512-hunJbvy/6OLjCD0uuhLdp0mMPzP/yd2ssd1t2FCJsaA7wkWhpbp9xfuNVpv7Ll4jFhzp6T4LAupSiV9uOeg0VQ==", "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "web-streams-polyfill": "^3.0.3" } }, - "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", "dev": true }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "escape-string-regexp": "^1.0.5" } }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "flat-cache": "^3.0.4" } }, - "for-in": { + "fill-keys": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, "requires": { - "for-in": "^1.0.1" + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "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==", "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "to-regex-range": "^5.0.1" } }, - "format-util": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz", - "integrity": "sha1-Ay3KShFiYqEsQ/TD7IVmQWxbLZU=" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { - "map-cache": "^0.2.2" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" } }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" } }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "dev": true, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { - "minipass": "^2.6.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "follow-redirects": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, - "optional": true, "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, + "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, - "optional": true, "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } + "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 }, - "nopt": { - "version": "4.0.1", - "bundled": true, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "shebang-regex": "^3.0.0" } }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true + "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 }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "isexe": "^2.0.0" } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "format-util": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", + "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fp-and-or": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.3.tgz", + "integrity": "sha512-wJaE62fLaB3jCYvY2ZHjZvmKK2iiLiiehX38rz5QZxtdN8fVPJDeZUiVvJrHStdTc+23LHlyZuSEKgFc0pxi2g==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-readfile-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-2.0.1.tgz", + "integrity": "sha1-gAI4I5gfn//+AWCei+Zo9prknnA=", + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "fs-writefile-promise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-writefile-promise/-/fs-writefile-promise-1.0.3.tgz", + "integrity": "sha1-4C+bWP/CVe2CKtx6ARFPRF1I0GM=", + "requires": { + "mkdirp-promise": "^1.0.0", + "pinkie-promise": "^1.0.0" + }, + "dependencies": { + "pinkie-promise": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", + "integrity": "sha1-0dpn9UglY7t89X8oauKCLs+/NnA=", "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "pinkie": "^1.0.0" } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "wrappy": "1" + "number-is-nan": "^1.0.0" } }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { + "string-width": { "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } + } + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "requires": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "dependencies": { + "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 }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, - "optional": true, "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "readable-stream": { - "version": "2.3.6", - "bundled": true, + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4133,204 +5810,157 @@ "util-deprecate": "~1.0.1" } }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { - "version": "3.0.1", - "bundled": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "optional": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" } }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "optional": true, "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, - "optional": true, "requires": { - "string-width": "^1.0.2 || 2" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true } } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "genfun": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, "requires": { "pump": "^3.0.0" + } + }, + "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, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getopts": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", + "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "git-raw-commits": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", + "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "requires": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" }, "dependencies": { - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "requires": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "getopts": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", - "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, "requires": { - "assert-plus": "^1.0.0" + "ini": "^1.3.2" } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4341,51 +5971,61 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } }, "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", "dev": true, "requires": { - "ini": "^1.3.4" + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + } } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "type-fest": "^0.20.2" } }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } } }, - "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 - }, "good-console": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/good-console/-/good-console-8.0.0.tgz", @@ -4395,6 +6035,18 @@ "joi": "14.x.x", "json-stringify-safe": "5.x.x", "moment": "2.x.x" + }, + "dependencies": { + "joi": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", + "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "requires": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + } } }, "good-squeeze": { @@ -4406,6 +6058,11 @@ "hoek": "4.2.x" }, "dependencies": { + "fast-safe-stringify": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz", + "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==" + }, "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", @@ -4433,493 +6090,66 @@ } }, "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "grpc": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.0.tgz", - "integrity": "sha512-zq1rUh2uzfMqSfQ3bZvlQuX5yKfd/2vob+l9sK5Qma6P33m7UvyMCVW70+Wz0WTzy9W2A94eQD5XIOxKnZhsYQ==", + "version": "1.24.9", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.9.tgz", + "integrity": "sha512-BOq1AJocZJcG/6qyX3LX2KvKy91RIix10GFLhqWg+1L6b73uWIN2w0cq+lSi0q9mXfkjeFaBz83+oau7oJqG3Q==", "requires": { + "@mapbox/node-pre-gyp": "^1.0.4", + "@types/bytebuffer": "^5.0.40", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", - "node-pre-gyp": "^0.13.0", "protobufjs": "^5.0.3" }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.2", - "bundled": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true - }, - "fs-minipass": { - "version": "1.2.6", - "bundled": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.4", - "bundled": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "bundled": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "bundled": true - } - } - }, - "ms": { - "version": "2.1.2", - "bundled": true - }, - "needle": { - "version": "2.4.0", - "bundled": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.13.0", - "bundled": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true - }, - "npm-packlist": { - "version": "1.4.4", - "bundled": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true - }, "protobufjs": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", - "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", - "requires": { - "ascli": "~1", - "bytebuffer": "~5", - "glob": "^7.0.5", - "yargs": "^3.10.0" - } - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "sax": { - "version": "1.2.4", - "bundled": true - }, - "semver": { - "version": "5.7.1", - "bundled": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "tar": { - "version": "4.4.10", - "bundled": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.5", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", + "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", "requires": { - "string-width": "^1.0.2 || 2" + "ascli": "~1", + "bytebuffer": "~5", + "glob": "^7.0.5", + "yargs": "^3.10.0" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true } } }, "handlebars": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.5.tgz", - "integrity": "sha512-0Ce31oWVB7YidkaTq33ZxEbN+UDxMMgThvCe8ptgQViymL5DPis9uLdTA13MiRPhgvqyxIegugrP97iK3JeBHg==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { + "minimist": "^1.2.5", "neo-async": "^2.6.0", - "optimist": "^0.6.1", "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "hapi-openapi": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/hapi-openapi/-/hapi-openapi-1.2.4.tgz", - "integrity": "sha512-G/X0B9vB/xyVCHoPWXlH27TCzbJlSpNrS4szRJsBphVR+8GvtjKK2q6ZtNO1eo1C6W5H8BSA3tk16v2J/uRuTw==", - "requires": { - "dot-prop": "^4.2.0", - "enjoi": "^4.0.0", - "hoek": "^5.0.3", - "joi": "^13.6.0", - "js-yaml": "^3.11.0", - "merge-object-files": "^2.0.0", - "swagger-parser": "^4.1.0" + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" }, "dependencies": { - "hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==" + "uglify-js": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", + "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", + "dev": true, + "optional": true }, - "joi": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", - "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", - "requires": { - "hoek": "5.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true } } }, @@ -4929,19 +6159,42 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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==" + } } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -4950,55 +6203,39 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, - "has-value": { + "has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "has-symbols": "^1.0.2" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "has-yarn": { "version": "2.1.0", @@ -5007,47 +6244,85 @@ "dev": true }, "hash-it": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/hash-it/-/hash-it-4.0.4.tgz", - "integrity": "sha512-LC8xgrdjR3iW2hs7Vb18FFDIyv+hZHFAwJM11SKLwwI4LdoniT+ZmrHk7b6vYjoo7KPFPcGZ/8u2XybBWzWtsw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hash-it/-/hash-it-4.1.0.tgz", + "integrity": "sha512-YUXBmvWycqr0qVb7RhNyJ2ItiPNaD5iKZ9moDaxduyfT8I9d79F9Zf8Ts2RAG7g6NPwD8351dSqxsD07tznSmQ==", "requires": { - "curriable": "^1.1.0", - "fast-stringify": "^1.1.1", - "json-prune": "^1.1.0" + "curriable": "^1.1.0" } }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + }, + "highlightjs": { + "version": "9.16.2", + "resolved": "https://registry.npmjs.org/highlightjs/-/highlightjs-9.16.2.tgz", + "integrity": "sha512-FK1vmMj8BbEipEy8DLIvp71t5UsC7n2D6En/UfM/91PCwmOpj6f2iu0Y0coRC62KSRHHC+dquM2xMULV/X7NFg==" + }, "hoek": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, "requires": { - "parse-passwd": "^1.0.0" + "lru-cache": "^6.0.0" } }, - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" } }, "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "dev": true }, "http-errors": { @@ -5063,28 +6338,29 @@ } }, "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "requires": { - "agent-base": "4", - "debug": "3.1.0" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "2.1.2" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -5093,33 +6369,102 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, + "http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==" + }, "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "agent-base": "6", + "debug": "4" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "httpsnippet": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/httpsnippet/-/httpsnippet-1.25.0.tgz", + "integrity": "sha512-jobE6S923cLuf5BPG6Jf+oLBRkPzv2RPp0dwOHcWwj/t9FwV/t9hyZ46kpT3Q5DHn9iFNmGhrcmmFUBqyjoTQg==", + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "debug": "^2.2.0", + "event-stream": "3.3.4", + "form-data": "3.0.0", + "fs-readfile-promise": "^2.0.1", + "fs-writefile-promise": "^1.0.3", + "har-validator": "^5.0.0", + "pinkie-promise": "^2.0.0", + "stringify-object": "^3.3.0" + }, + "dependencies": { + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "requires": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "requires": { + "through": "2" + } + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "requires": { + "duplexer": "~0.1.1" } } } }, + "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 + }, "humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -5137,12 +6482,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -5150,9 +6489,9 @@ "dev": true }, "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", "dev": true, "requires": { "minimatch": "^3.0.4" @@ -5175,13 +6514,21 @@ "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } } }, "import-lazy": { @@ -5191,13 +6538,13 @@ "dev": true }, "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", "dev": true, "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" } }, "imurmurhash": { @@ -5206,6 +6553,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -5227,101 +6580,30 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - } + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" } }, "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" }, "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" }, "ip": { "version": "1.1.5", @@ -5329,113 +6611,79 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "requires": { - "ci-info": "^2.0.0" + "has-bigints": "^1.0.1" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } + "binary-extensions": "^2.0.0" } }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "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, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } + "ci-info": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", + "requires": { + "has": "^1.0.3" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "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, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-extglob": { "version": "2.1.1", @@ -5443,12 +6691,9 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-generator-fn": { "version": "2.1.0", @@ -5457,50 +6702,53 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "requires": { "is-extglob": "^2.1.1" } }, "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, "is-npm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", - "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } + "has-tostringtag": "^1.0.0" } }, "is-obj": { @@ -5509,19 +6757,16 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", "dev": true }, "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } + "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 }, "is-plain-obj": { "version": "1.1.0", @@ -5529,74 +6774,90 @@ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "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, "requires": { - "has": "^1.0.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "is-relative": { + "is-regexp": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "requires": { - "is-unc-path": "^1.0.0" - } + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "text-extensions": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "call-bind": "^1.0.0" } }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" }, "is-yarn-global": { "version": "0.3.0", @@ -5622,35 +6883,37 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.2.tgz", + "integrity": "sha512-o5+eTUYzCJ11/+JhW5/FUCdfsdoYVdQ/8I/OveE2XsjehYn5DdeSnNQAbjYaO8gQ6hvGTN6GM6ddQqpTVG5j8g==", "dev": true }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "dependencies": { "semver": { @@ -5661,688 +6924,1671 @@ } } }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "istanbul-reports": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.5.tgz", + "integrity": "sha512-vDMzXcpQN4Ycaqu+vO7LX8pZwNNoKMhc+gSp6q1D8S6ftRk8gNW8cni3YFxknP95jxzQo23Lul0BI2FrWgnwYQ==", + "dev": true, + "requires": { + "@jest/core": "^27.2.5", + "import-local": "^3.0.2", + "jest-cli": "^27.2.5" + }, + "dependencies": { + "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 + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-cli": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.5.tgz", + "integrity": "sha512-XzfcOXi5WQrXqFYsDxq5RDOKY4FNIgBgvgf3ZBz4e/j5/aWep5KnsAYH5OFPMdX/TP/LFsYQMRH7kzJUMh6JKg==", + "dev": true, + "requires": { + "@jest/core": "^27.2.5", + "@jest/test-result": "^27.2.5", + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.2.5", + "jest-util": "^27.2.5", + "jest-validate": "^27.2.5", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "jest-changed-files": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.2.5.tgz", + "integrity": "sha512-jfnNJzF89csUKRPKJ4MwZ1SH27wTmX2xiAIHUHrsb/OYd9Jbo4/SXxJ17/nnx6RIifpthk3Y+LEeOk+/dDeGdw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "isexe": "^2.0.0" } } } }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "jest-circus": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.5.tgz", + "integrity": "sha512-eyL9IcrAxm3Saq3rmajFCwpaxaRMGJ1KJs+7hlTDinXpJmeR3P02bheM3CYohE7UfwOBmrFMJHjgo/WPcLTM+Q==", "dev": true, "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" + "@jest/environment": "^27.2.5", + "@jest/test-result": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.2.5", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.2.5", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-runtime": "^27.2.5", + "jest-snapshot": "^27.2.5", + "jest-util": "^27.2.5", + "pretty-format": "^27.2.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "jest-config": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.5.tgz", + "integrity": "sha512-QdENtn9b5rIIYGlbDNEcgY9LDL5kcokJnXrp7x8AGjHob/XFqw1Z6p+gjfna2sUulQsQ3ce2Fvntnv+7fKYDhQ==", "dev": true, "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.2.5", + "@jest/types": "^27.2.5", + "babel-jest": "^27.2.5", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "jest-circus": "^27.2.5", + "jest-environment-jsdom": "^27.2.5", + "jest-environment-node": "^27.2.5", + "jest-get-type": "^27.0.6", + "jest-jasmine2": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.5", + "jest-runner": "^27.2.5", + "jest-util": "^27.2.5", + "jest-validate": "^27.2.5", + "micromatch": "^4.0.4", + "pretty-format": "^27.2.5" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 }, - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" + "has-flag": "^4.0.0" } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + } + } + }, + "jest-diff": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.5.tgz", + "integrity": "sha512-7gfwwyYkeslOOVQY4tVq5TaQa92mWfC9COsVYMNVYyJTOYAqbIkoD3twi5A+h+tAPtAelRxkqY6/xu+jwTr0dA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-convert": "^2.0.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "color-name": "~1.1.4" } }, - "y18n": { + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "has-flag": "^4.0.0" } } } }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "requires": { - "detect-newline": "^2.1.0" + "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.5.tgz", + "integrity": "sha512-HUPWIbJT0bXarRwKu/m7lYzqxR4GM5EhKOsu0z3t0SKtbFN6skQhpAUADM4qFShBXb9zoOuag5lcrR1x/WM+Ag==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.6", + "jest-util": "^27.2.5", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.5.tgz", + "integrity": "sha512-QtRpOh/RQKuXniaWcoFE2ElwP6tQcyxHu0hlk32880g0KczdonCs5P1sk5+weu/OVzh5V4Bt1rXuQthI01mBLg==", "dev": true, "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" + "@jest/environment": "^27.2.5", + "@jest/fake-timers": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.2.5", + "jest-util": "^27.2.5", + "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.5.tgz", + "integrity": "sha512-0o1LT4grm7iwrS8fIoLtwJxb/hoa3GsH7pP10P02Jpj7Mi4BXy65u46m89vEM2WfD1uFJQ2+dfDiWZNA2e6bJg==", "dev": true, "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" + "@jest/environment": "^27.2.5", + "@jest/fake-timers": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "jest-mock": "^27.2.5", + "jest-util": "^27.2.5" } }, "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", "dev": true }, "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.5.tgz", + "integrity": "sha512-pzO+Gw2WLponaSi0ilpzYBE0kuVJstoXBX8YWyUebR8VaXuX4tzzn0Zp23c/WaETo7XYTGv2e8KdnpiskAFMhQ==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", + "@jest/types": "^27.2.5", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.2.5", + "jest-worker": "^27.2.5", + "micromatch": "^4.0.4", "walker": "^1.0.7" } }, "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.5.tgz", + "integrity": "sha512-hdxY9Cm/CjLqu2tXeAoQHPgA4vcqlweVXYOg1+S9FeFdznB9Rti+eEBKDDkmOy9iqr4Xfbq95OkC4NFbXXPCAQ==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", + "@jest/environment": "^27.2.5", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^24.9.0", + "expect": "^27.2.5", "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" + "jest-each": "^27.2.5", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-runtime": "^27.2.5", + "jest-snapshot": "^27.2.5", + "jest-util": "^27.2.5", + "pretty-format": "^27.2.5", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-junit": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-9.0.0.tgz", - "integrity": "sha512-jnABGjL5pd2lhE1w3RIslZSufFbWQZGx8O3eluDES7qKxQuonXMtsPIi+4AKl4rtjb4DvMAjwLi4eHukc2FP/Q==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-13.0.0.tgz", + "integrity": "sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg==", "dev": true, "requires": { - "jest-validate": "^24.9.0", - "mkdirp": "^0.5.1", - "strip-ansi": "^5.2.0", - "uuid": "^3.3.3", + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", "xml": "^1.0.1" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } }, "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.5.tgz", + "integrity": "sha512-HYsi3GUR72bYhOGB5C5saF9sPdxGzSjX7soSQS+BqDRysc7sPeBwPbhbuT8DnOpijnKjgwWQ8JqvbmReYnt3aQ==", "dev": true, "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.5" } }, "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz", + "integrity": "sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg==", "dev": true, "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "chalk": "^4.0.0", + "jest-diff": "^27.2.5", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.5.tgz", + "integrity": "sha512-ggXSLoPfIYcbmZ8glgEJZ8b+e0Msw/iddRmgkoO7lDAr9SmI65IIfv7VnvTnV4FGnIIUIjzM+fHRHO5RBvyAbQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.2.5", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.2.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.2.5.tgz", + "integrity": "sha512-HiMB3LqE9RzmeMzZARi2Bz3NoymxyP0gCid4y42ca1djffNtYFKgI220aC1VP1mUZ8rbpqZbHZOJ15093bZV/Q==", "dev": true, "requires": { - "@jest/types": "^24.9.0" + "@jest/types": "^27.2.5", + "@types/node": "*" } }, "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", "dev": true }, "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", "dev": true }, "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.5.tgz", + "integrity": "sha512-q5irwS3oS73SKy3+FM/HL2T7WJftrk9BRzrXF92f7net5HMlS7lJMg/ZwxLB4YohKqjSsdksEw7n/jvMxV7EKg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "chalk": "^4.0.0", + "escalade": "^3.1.1", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.5", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.2.5", + "jest-validate": "^27.2.5", + "resolve": "^1.20.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.5.tgz", + "integrity": "sha512-BSjefped31bcvvCh++/pN9ueqqN1n0+p8/58yScuWfklLm2tbPbS9d251vJhAy0ZI2pL/0IaGhOTJrs9Y4FJlg==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.2.5" } }, "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.5.tgz", + "integrity": "sha512-n41vw9RLg5TKAnEeJK9d6pGOsBOpwE89XBniK+AD1k26oIIy3V7ogM1scbDjSheji8MUPC9pNgCrZ/FHLVDNgg==", + "dev": true, + "requires": { + "@jest/console": "^27.2.5", + "@jest/environment": "^27.2.5", + "@jest/test-result": "^27.2.5", + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.2.5", + "jest-environment-node": "^27.2.5", + "jest-haste-map": "^27.2.5", + "jest-leak-detector": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-resolve": "^27.2.5", + "jest-runtime": "^27.2.5", + "jest-util": "^27.2.5", + "jest-worker": "^27.2.5", "source-map-support": "^0.5.6", - "throat": "^4.0.0" + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.5.tgz", + "integrity": "sha512-N0WRZ3QszKyZ3Dm27HTBbBuestsSd3Ud5ooVho47XZJ8aSKO/X1Ag8M1dNx9XzfGVRNdB/xCA3lz8MJwIzPLLA==", + "dev": true, + "requires": { + "@jest/console": "^27.2.5", + "@jest/environment": "^27.2.5", + "@jest/fake-timers": "^27.2.5", + "@jest/globals": "^27.2.5", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.2.5", + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", "exit": "^0.1.2", "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-mock": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.5", + "jest-snapshot": "^27.2.5", + "jest-util": "^27.2.5", + "jest-validate": "^27.2.5", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.2.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "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 + }, + "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 + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "path-key": "^3.0.0" } }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } } } }, "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } }, "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.5.tgz", + "integrity": "sha512-2/Jkn+VN6Abwz0llBltZaiJMnL8b1j5Bp/gRIxe9YR3FCEh9qp0TXVV0dcpTGZ8AcJV1SZGQkczewkI9LP5yGw==", "dev": true, "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", + "@jest/transform": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.2.5", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.2.5", + "jest-get-type": "^27.0.6", + "jest-haste-map": "^27.2.5", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-resolve": "^27.2.5", + "jest-util": "^27.2.5", "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" + "pretty-format": "^27.2.5", + "semver": "^7.3.2" }, "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.5.tgz", + "integrity": "sha512-QRhDC6XxISntMzFRd/OQ6TGsjbzA5ONO0tlAj2ElHs155x1aEr0rkYJBEysG6H/gZVH3oGFzCdAB/GA8leh8NQ==", "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.5.tgz", + "integrity": "sha512-XgYtjS89nhVe+UfkbLgcm+GgXKWgL80t9nTcNeejyO3t0Sj/yHE8BtIJqjZu9NXQksYbGImoQRXmQ1gP+Guffw==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.6", + "leven": "^3.1.0", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" + "jest-watcher": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.5.tgz", + "integrity": "sha512-umV4qGozg2Dn6DTTtqAh9puPw+DGLK9AQas7+mWjiK8t0fWMpxKg8ZXReZw7L4C88DqorsGUiDgwHNZ+jkVrkQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.2.5", + "@jest/types": "^27.2.5", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.2.5", + "string-length": "^4.0.1" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.5.tgz", + "integrity": "sha512-HTjEPZtcNKZ4LnhSp02NEH4vE+5OpJ0EsOWYvGQpHgUMLngydESAAMH5Wd/asPf29+XUDQZszxpLg1BkIIA2aw==", "dev": true, "requires": { + "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" + "supports-color": "^8.0.0" }, "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } }, + "jgexml": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jgexml/-/jgexml-0.4.4.tgz", + "integrity": "sha512-j0AzSWT7LXy3s3i1cdv5NZxUtscocwiBxgOLiEBfitCehm8STdXVrcOlbAWsJFLCq1elZYpQlGqA9k8Z+n9iJA==" + }, "jju": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", @@ -6350,84 +8596,95 @@ "dev": true }, "joi": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", - "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.2.tgz", + "integrity": "sha512-Lm56PP+n0+Z2A2rfRvsfWVDXGEWjXxatPopkQ8qQ5mxCEhwHG+Ettgg5o98FFaxilOxozoa14cFhrE/hOzh/Nw==", "requires": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" } }, "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 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true }, "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true }, "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" } } } @@ -6450,6 +8707,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-parse-helpfulerror": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", @@ -6459,53 +8722,76 @@ "jju": "^1.1.0" } }, - "json-prune": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/json-prune/-/json-prune-1.1.0.tgz", - "integrity": "sha1-I+L60QiTKyVQUOPxpwUAwrSqMMc=" + "json-pointer": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.1.tgz", + "integrity": "sha512-3OvjqKdCBvH41DLpV4iSt6v2XhZXV1bPB4OROuknvUXI7ZQNofieCPkmE26stEJ9zdQuvIxDHCuYhfgxFAAs+Q==", + "requires": { + "foreach": "^2.0.4" + } }, "json-rules-engine": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/json-rules-engine/-/json-rules-engine-4.1.0.tgz", - "integrity": "sha512-L1wswOKPTw8q318OyVne4Tk2RX0LZSdY7oELEq5Rq2ventYjBge/fNgxzvNbbj3lgeGC43ZlPhHL7M/dj6yBfg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/json-rules-engine/-/json-rules-engine-5.0.2.tgz", + "integrity": "sha512-taan5IByJGmw6CxcJPNoLsy6uQUqyfITMuT5u5SyAHtYDtWMbpq5VdFx460jVJ0ufvI76aDHbJET8pI4EwYF/w==", "requires": { "clone": "^2.1.2", "events": "^3.0.0", "hash-it": "^4.0.4", - "lodash.isobjectlike": "^4.0.0", - "selectn": "^1.1.2" + "jsonpath-plus": "^1.1.0", + "lodash.isobjectlike": "^4.0.0" } }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-ref-parser": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-5.1.3.tgz", - "integrity": "sha512-CpDFlBwz/6la78hZxyB9FECVKGYjIIl3Ms3KLqFj99W7IIb7D00/RDgc++IGB4BBALl0QRhh5m4q5WNSopvLtQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-1.4.1.tgz", + "integrity": "sha1-wMLkOL8HlnI7AkUbrovH3Qs3/tA=", + "dev": true, "requires": { "call-me-maybe": "^1.0.1", - "debug": "^3.1.0", - "js-yaml": "^3.12.0", - "ono": "^4.0.6" + "debug": "^2.2.0", + "es6-promise": "^3.0.2", + "js-yaml": "^3.4.6", + "ono": "^2.0.1" }, "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "requires": { - "ms": "^2.1.1" + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" } + }, + "ono": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/ono/-/ono-2.2.5.tgz", + "integrity": "sha1-2vCUiLURdNp6fkJ136sxtDj/oOM=", + "dev": true } } }, "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==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -6518,13 +8804,22 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json-to-ast": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json-to-ast/-/json-to-ast-2.1.0.tgz", + "integrity": "sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==", + "requires": { + "code-error-fragment": "0.0.230", + "grapheme-splitter": "^1.0.4" + } + }, "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "^1.2.5" } }, "jsonlines": { @@ -6539,22 +8834,15 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, - "jsonpath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.0.2.tgz", - "integrity": "sha512-rmzlgFZiQPc6q4HDyK8s9Qb4oxBnI5sF61y/Co5PV0lc3q2bIuRsNdueVbhoSHdKM4fxeimphOAtfz47yjCfeA==", - "requires": { - "esprima": "1.2.2", - "static-eval": "2.0.2", - "underscore": "1.7.0" - }, - "dependencies": { - "esprima": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha1-dqD9Zvz+FU/SkmZ9wmQBl1CxZXs=" - } - } + "jsonpath-plus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-1.1.0.tgz", + "integrity": "sha512-ydqTBOuLcFCUr9e7AxJlKCFgxzEQ03HjnIim0hJSdk2NxD8MOsaMOrRgP6XWEm5q3VuDY5+cRT1DM9vLlGo/qA==" + }, + "jsonpointer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz", + "integrity": "sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg==" }, "jsonwebtoken": { "version": "8.5.1", @@ -6571,12 +8859,24 @@ "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^5.6.0" + }, + "dependencies": { + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + } } }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -6585,19 +8885,19 @@ } }, "jsx-ast-utils": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz", - "integrity": "sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", "dev": true, "requires": { - "array-includes": "^3.0.3", - "object.assign": "^4.1.0" + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" } }, "just-extend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", - "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" }, "jwa": { "version": "1.4.1", @@ -6610,12 +8910,24 @@ } }, "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", "requires": { - "jwa": "^1.4.1", + "jwa": "^2.0.0", "safe-buffer": "^5.0.1" + }, + "dependencies": { + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + } } }, "keyv": { @@ -6628,9 +8940,12 @@ } }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } }, "kleur": { "version": "3.0.3", @@ -6639,41 +8954,49 @@ "dev": true }, "knex": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.20.1.tgz", - "integrity": "sha512-vQvlzsCw4kkqWLmUFVhPX8H4KrfSLVSVGbMJVo4fhJ8N5fN+CH0LzgAmQBh0iwbJY7x8Sk3T4pEjnUlUKjnCPw==", - "requires": { - "bluebird": "^3.7.1", - "colorette": "1.1.0", - "commander": "^3.0.2", - "debug": "4.1.1", + "version": "0.95.11", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.11.tgz", + "integrity": "sha512-grDetD91O8VoQVCFqeWTgkzdq5406W6rggF/lK1hHuwzmjDs/0m9KxyncGdZbklTi7aUgHvw3+Cfy4x7FvpdaQ==", + "requires": { + "colorette": "1.2.1", + "commander": "^7.1.0", + "debug": "4.3.2", + "escalade": "^3.1.1", + "esm": "^3.2.25", "getopts": "2.2.5", - "inherits": "~2.0.4", - "interpret": "^1.2.0", - "liftoff": "3.1.0", - "lodash": "^4.17.15", - "mkdirp": "^0.5.1", - "pg-connection-string": "2.1.0", - "tarn": "^2.0.0", - "tildify": "2.0.0", - "uuid": "^3.3.3", - "v8flags": "^3.1.3" + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "0.7.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.1", + "tildify": "2.0.0" }, "dependencies": { "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, "kuler": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", - "requires": { - "colornames": "^1.1.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "latest-version": { "version": "5.1.0", @@ -6684,33 +9007,32 @@ "package-json": "^6.3.0" } }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "^2.0.0" } }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, "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 + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "libnpmconfig": { @@ -6722,21 +9044,56 @@ "figgy-pudding": "^3.5.1", "find-up": "^3.0.0", "ini": "^1.3.5" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "uc.micro": "^1.0.1" } }, "load-json-file": { @@ -6749,22 +9106,28 @@ "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.camelcase": { "version": "4.3.0", @@ -6776,6 +9139,18 @@ "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -6794,13 +9169,20 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true }, "lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, "lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", @@ -6821,38 +9203,44 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" }, + "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==" + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true }, "logform": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", - "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", "requires": { "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", + "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", "triple-beam": "^1.3.0" } }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==" - }, "long": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6869,79 +9257,140 @@ "dev": true }, "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, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "semver": "^6.0.0" }, "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "make-fetch-happen": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.1.tgz", - "integrity": "sha512-b4dfaMvUDR67zxUq1+GN7Ke9rH5WvGRmoHuMH7l+gmUCR2tCXFP6mpeJ9Dp+jB6z8mShRopSf1vLRBhRs8Cu5w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", "dev": true, "requires": { - "agentkeepalive": "^3.4.1", - "cacache": "^12.0.0", - "http-cache-semantics": "^3.8.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "node-fetch-npm": "^2.0.2", - "promise-retry": "^1.1.1", - "socks-proxy-agent": "^4.0.0", - "ssri": "^6.0.0" + "tmpl": "1.0.x" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" + } } }, - "make-iterator": { + "markdown-it-attrs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-1.2.1.tgz", + "integrity": "sha512-EYYKLF9RvQJx1Etsb6EsBGWL7qNQLpg9BRej5f06+UdX75T5gvldEn7ts6bkLIQqugE15SGn4lw1CXDS1A+XUA==" + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" + }, + "markdown-it-lazy-headers": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/markdown-it-lazy-headers/-/markdown-it-lazy-headers-0.1.3.tgz", + "integrity": "sha1-5w3U2nnIepzoLKRwG4t8Di1yKXs=" + }, + "mdurl": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "requires": { - "kind-of": "^6.0.2" - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "requires": { - "object-visit": "^1.0.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" } }, "memory-cache": { @@ -6949,16 +9398,133 @@ "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", "integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo=" }, + "meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + } + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-object-files": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-object-files/-/merge-object-files-2.0.0.tgz", - "integrity": "sha512-3PqpQPQ9x8ONbUB30TnQw6+giAynlr7zPuGX0RCTHp/oxG0R0A6+WIFH7soFLoZnIKomA7thQrZ+oYFRNzzTww==" + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge-options": { "version": "1.0.1", @@ -6975,51 +9541,49 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", "requires": { - "mime-db": "1.40.0" - }, - "dependencies": { - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - } + "mime-db": "1.50.0" } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "mimic-response": { "version": "1.0.1", @@ -7027,6 +9591,12 @@ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -7036,93 +9606,128 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } }, "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "dev": true, "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "minipass": "^3.0.0" } }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", "dev": true, "requires": { - "minipass": "^2.9.0" + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" } }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } + "minipass": "^3.0.0" } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "mkdirp-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-1.1.0.tgz", + "integrity": "sha1-LISJPtZ24NmPsY+5piEv0bK5qBk=" + }, + "mock-json-schema": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mock-json-schema/-/mock-json-schema-1.1.1.tgz", + "integrity": "sha512-YV23vlsLP1EEOy0EviUvZTluXjLR+rhMzeayP2rcDiezj3RW01MhOSQkbQskdtg0K2fnGas5LKbSXgNjAOSX4A==", "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } + "lodash": "^4.17.21" } }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, "module-not-found-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", @@ -7130,80 +9735,75 @@ "dev": true }, "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "mustache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.1.0.tgz", - "integrity": "sha512-3Bxq1R5LBZp7fbFPZzFe5WN4s0q3+gxZaZuZVY+QctYJiCiVgXHOTIC0/HgZuOPFt/6BQcx5u0H2CUOxT/RoGQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "mysql": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz", - "integrity": "sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", "requires": { - "bignumber.js": "7.2.1", - "readable-stream": "2.3.6", + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" }, "dependencies": { "bignumber.js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } } } }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" }, "natural-compare": { "version": "1.4.0", @@ -7211,87 +9811,102 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, - "nested-error-stacks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", - "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "nise": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", - "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", + "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", "requires": { - "@sinonjs/formatio": "^3.2.1", + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^4.1.0", "path-to-regexp": "^1.7.0" - } - }, - "node-alias": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/node-alias/-/node-alias-1.0.4.tgz", - "integrity": "sha1-HxuRa1a56iQcATX5fO1pQPVW8pI=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "lodash": "^4.2.0" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "isarray": "0.0.1" } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true } } }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz", + "integrity": "sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==", + "requires": { + "data-uri-to-buffer": "^3.0.1", + "fetch-blob": "^3.1.2" + } }, - "node-fetch-npm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", - "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "requires": { + "http2-client": "^1.2.5" + } + }, + "node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", "dev": true, "requires": { - "encoding": "^0.1.11", - "json-parse-better-errors": "^1.0.0", - "safe-buffer": "^5.1.1" + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "node-int64": { @@ -7306,26 +9921,35 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", "dev": true }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" + "process-on-spawn": "^1.0.0" + } + }, + "node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha1-271K8SE04uY1wkXvk//Pb2BnOl0=", + "requires": { + "es6-promise": "^3.2.1" } }, - "node-rdkafka": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/node-rdkafka/-/node-rdkafka-2.7.1.tgz", - "integrity": "sha512-LrPTNtAoENJedyvYDI/AhBieq+aaFD+ImEIFAxJzL1HAYDZdCwe+TjivSK6N4YLXtxlbXVA1i43DK04VOWebeA==", + "node-releases": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", + "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "dev": true + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "requires": { - "bindings": "^1.3.1", - "nan": "^2.14.0" + "abbrev": "1" } }, "normalize-package-data": { @@ -7338,245 +9962,655 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + } } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true }, "npm-audit-resolver": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/npm-audit-resolver/-/npm-audit-resolver-2.1.0.tgz", - "integrity": "sha512-8VaG7p3tbP0+JbpDKldQueZvh9oUcr3H/C2FIbcIhYBANAQ1kCIhUqYOxVFjG3RKEV9G1coIFzUOxBoPyyejNg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/npm-audit-resolver/-/npm-audit-resolver-2.3.1.tgz", + "integrity": "sha512-vJF4v4UxMKGFdbGRl2II6oJ8dCpBFfhD1oONZMAfept4RM0AyHVBEjZgDrpfEJ4EjNiO9NZLxon5Fl8bM2s6dQ==", "dev": true, "requires": { - "audit-resolve-core": "^1.1.7", + "audit-resolve-core": "^1.1.8", "chalk": "^2.4.2", - "djv": "^2.1.2", + "djv": "^2.1.4", "jsonlines": "^0.1.1", "read": "^1.0.7", "spawn-shell": "^2.1.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^18.1.3", + "yargs-unparser": "^1.6.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } } }, "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } }, "npm-check-updates": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-3.2.0.tgz", - "integrity": "sha512-Gqxd6Fv+EoGNKg2thclx3LPs9dHa1Tp/R+/59iYAgbliJ5NsDd/D6j6kjhnLtKh+7XMX7co3gTrVzsSqTPNRAg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-11.8.5.tgz", + "integrity": "sha512-IYSHjlWe8UEugDy7X0qjBeJwcni4DlcWdBK4QQEbwgkNlEDlXyd4yQJYWFumKaJzrp/n5/EcvaboXsBD1Er/pw==", "dev": true, "requires": { - "chalk": "^2.4.2", + "chalk": "^4.1.2", "cint": "^8.2.1", - "cli-table": "^0.3.1", - "commander": "^3.0.2", - "fast-diff": "^1.2.0", - "find-up": "4.1.0", - "get-stdin": "^7.0.0", + "cli-table": "^0.3.6", + "commander": "^6.2.1", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^0.1.3", + "get-stdin": "^8.0.0", + "globby": "^11.0.4", + "hosted-git-info": "^4.0.2", "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", "libnpmconfig": "^1.2.1", - "lodash": "^4.17.15", - "node-alias": "^1.0.4", - "pacote": "^9.5.8", + "lodash": "^4.17.21", + "minimatch": "^3.0.4", + "p-map": "^4.0.0", + "pacote": "^11.3.5", + "parse-github-url": "^1.0.2", "progress": "^2.0.3", - "prompts": "^2.2.1", - "rc-config-loader": "^2.0.4", - "requireg": "^0.2.2", - "semver": "^6.3.0", + "prompts": "^2.4.1", + "rc-config-loader": "^4.0.0", + "remote-git-tags": "^3.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", "semver-utils": "^1.1.4", - "spawn-please": "^0.3.0", - "update-notifier": "^3.0.1" + "spawn-please": "^1.0.0", + "update-notifier": "^5.1.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "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, "requires": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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, "requires": { - "p-locate": "^4.1.0" + "yocto-queue": "^0.1.0" } }, "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==", + "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, "requires": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" } }, - "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 + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "requires": { + "semver": "^7.1.1" + }, + "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, "npm-package-arg": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", "dev": true, "requires": { - "hosted-git-info": "^2.7.1", - "osenv": "^0.1.5", - "semver": "^5.6.0", + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", + "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", "dev": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" } }, "npm-pick-manifest": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", - "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", "dev": true, "requires": { - "figgy-pudding": "^3.5.1", - "npm-package-arg": "^6.0.0", - "semver": "^5.4.1" + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "npm-registry-fetch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", - "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", "dev": true, "requires": { - "JSONStream": "^1.3.4", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.4.1", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - } + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" } }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, "requires": { "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "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 + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "requires": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + } + }, + "oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "requires": { - "is-descriptor": "^0.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "yargs": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==" + }, + "oas-validator": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-4.0.8.tgz", + "integrity": "sha512-bIt8erTyclF7bkaySTtQ9sppqyVc+mAlPi7vPzCLVHJsL9nrivQjc/jHLX/o+eGbxHd6a6YBwuY/Vxa6wGsiuw==", + "requires": { + "ajv": "^5.5.2", + "better-ajv-errors": "^0.6.7", + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.1.3", + "oas-resolver": "^2.4.3", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.5", + "should": "^13.2.1", + "yaml": "^1.8.3" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "is-buffer": "^1.1.5" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" } } }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" }, "object-keys": { "version": "1.1.1", @@ -7584,98 +10618,59 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "es-abstract": "^1.19.1" } }, "object.fromentries": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz", - "integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.15.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "es-abstract": "^1.19.1" } }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" } }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "es-abstract": "^1.19.1" } }, "oer-utils": { @@ -7683,6 +10678,19 @@ "resolved": "https://registry.npmjs.org/oer-utils/-/oer-utils-1.3.4.tgz", "integrity": "sha1-sqmtvJK8GRVaKgDwRWg9Hm1KyCM=" }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7692,62 +10700,92 @@ } }, "one-time": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", - "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "ono": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", + "dev": true, "requires": { "format-util": "^1.0.3" } }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, + "openapi-backend": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/openapi-backend/-/openapi-backend-4.2.0.tgz", + "integrity": "sha512-eqdgJAjDbVZ7zhiIF68mlItFxqE48OPAM9nHHYx6BJMoGK2xInSBc2Oqp4dzsrsLIzoY8nVzK/vUtYktyXGb9Q==", "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } + "@apidevtools/json-schema-ref-parser": "^9.0.7", + "ajv": "^8.5.0", + "bath-es5": "^3.0.3", + "cookie": "^0.4.0", + "lodash": "^4.17.15", + "mock-json-schema": "^1.0.7", + "openapi-schema-validator": "^9.2.0", + "openapi-types": "^9.2.0", + "qs": "^6.9.3" + } + }, + "openapi-sampler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.1.0.tgz", + "integrity": "sha512-/LhZYKNBWphLEpbAG5BdpBZbIbmLgC4vTiTj8N/MV0LF9ptmKOiJ2nETVlacNjXHt7iqDgZDELJCIoZ3q5ZG6A==", + "requires": { + "@types/json-schema": "^7.0.7", + "json-pointer": "^0.6.1" + } + }, + "openapi-schema-validator": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/openapi-schema-validator/-/openapi-schema-validator-9.3.0.tgz", + "integrity": "sha512-KlvgZMWTu+H1FHFSZNAGj369uXl3BD1nXSIq+sXlG6P+OrsAHd3YORx0ZEZ3WGdu2LQrPGmtowGQavYXL+PLwg==", + "requires": { + "ajv": "^8.1.0", + "ajv-formats": "^2.0.2", + "lodash.merge": "^4.6.1", + "openapi-types": "^9.3.0" + } + }, + "openapi-types": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.3.0.tgz", + "integrity": "sha512-sR23YjmuwDSMsQVZDHbV9mPgi0RyniQlqR0AQxTC2/F3cpSjRFMH3CFPjoWvNqhC4OxPkDYNb2l8Mc1Me6D/KQ==" + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, "optjs": { @@ -7755,18 +10793,14 @@ "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "requires": { - "lcid": "^1.0.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, "os-shim": { @@ -7775,72 +10809,68 @@ "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", "dev": true }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, - "p-each-series": { + "p-defer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } }, "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 + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } }, "package-json": { "version": "6.5.0", @@ -7863,51 +10893,30 @@ } }, "pacote": { - "version": "9.5.9", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.9.tgz", - "integrity": "sha512-S1nYW9ly+3btn3VmwRAk2LG3TEh8mkrFdY+psbnHSk8oPODbZ28uG0Z0d3yI0EpqcpLR6BukoVRf3H4IbGCkPQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.3", - "cacache": "^12.0.2", - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.1.0", - "glob": "^7.1.3", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", + "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "dev": true, + "requires": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "minimatch": "^3.0.4", - "minipass": "^2.3.5", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "normalize-package-data": "^2.4.0", - "npm-package-arg": "^6.1.0", - "npm-packlist": "^1.1.12", - "npm-pick-manifest": "^3.0.0", - "npm-registry-fetch": "^4.0.0", - "osenv": "^0.1.5", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "protoduck": "^5.0.1", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.2", - "semver": "^5.6.0", - "ssri": "^6.0.1", - "tar": "^4.4.10", - "unique-filename": "^1.1.1", - "which": "^1.3.1" - } - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" } }, "parent-module": { @@ -7919,15 +10928,11 @@ "callsites": "^3.0.0" } }, - "parse-filepath": { + "parse-github-url": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true }, "parse-json": { "version": "4.0.0", @@ -7939,101 +10944,93 @@ "json-parse-better-errors": "^1.0.1" } }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + "parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=" }, "parse-strings-in-object": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-1.2.0.tgz", - "integrity": "sha512-lI8XgBWZ5COL0G2G6MsLqPSc4X/SnYPw5jGDiins/qzdOdlY493j/niCY9UiJqWjDoeY20k7vhEXvKRHTy6Dfw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-2.0.0.tgz", + "integrity": "sha512-hb50xDyEo8boMtyzB1IdVE4KcTNVbIirk/ZqC8na1irOf/70DyZS30y1FIIAUe9jyHJk9s2QoZ4aBNHR9NXHsg==" }, "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "requires": { + "parse5": "^6.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } - } + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "requires": { - "pify": "^3.0.0" + "through": "~2.3" } }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "pg-connection-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.1.0.tgz", - "integrity": "sha512-bhlV7Eq09JrRIvo1eKngpwuqKtJnNhZdpdOlvrPrA4dxqXPjxSrbNrfnIDmTpwMyRszrcV4kU5ZA4mMsQUrjdg==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pify": { "version": "3.0.0", @@ -8041,6 +11038,26 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "pinkie": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz", + "integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + } + } + }, "pirates": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", @@ -8060,58 +11077,151 @@ "load-json-file": "^5.2.0" }, "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, "load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", "dev": true, "requires": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } } }, - "pkg-config": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", - "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", - "dev": true, - "requires": { - "debug-log": "^1.0.0", - "find-root": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { - "find-up": "^3.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" } }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, "pre-commit": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", @@ -8162,9 +11272,10 @@ } }, "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true }, "prepend-http": { "version": "2.0.0", @@ -8173,21 +11284,27 @@ "dev": true }, "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.5.tgz", + "integrity": "sha512-+nYn2z9GgicO9JiqmY25Xtq8SYfZ/5VCpEU3pppHHNAhd1y+ZXxmNPd1evmNcAd6Hz4iBV2kf0UpGth5A/VJ7g==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" + "@jest/types": "^27.2.5", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "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 } } @@ -8197,12 +11314,29 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prom-client": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.1.0.tgz", + "integrity": "sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng==", + "requires": { + "tdigest": "^0.1.1" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -8210,23 +11344,23 @@ "dev": true }, "promise-retry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" + "err-code": "^2.0.2", + "retry": "^0.12.0" } }, "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "requires": { "kleur": "^3.0.3", - "sisteransi": "^1.0.3" + "sisteransi": "^1.0.5" } }, "prop-types": { @@ -8238,12 +11372,20 @@ "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.8.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } } }, "protobufjs": { - "version": "6.8.8", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", - "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -8255,8 +11397,8 @@ "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", "long": "^4.0.0" }, "dependencies": { @@ -8267,13 +11409,13 @@ } } }, - "protoduck": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", - "dev": true, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "requires": { - "genfun": "^5.0.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" } }, "proxyquire": { @@ -8294,27 +11436,28 @@ "dev": true }, "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true }, "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", "requires": { - "duplexify": "^3.6.0", + "duplexify": "^4.1.1", "inherits": "^2.0.3", - "pump": "^2.0.0" + "pump": "^3.0.0" } }, "punycode": { @@ -8322,10 +11465,40 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "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 + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true }, "randexp": { "version": "0.4.9", @@ -8335,14 +11508,6 @@ "requires": { "drange": "^1.0.0", "ret": "^0.2.0" - }, - "dependencies": { - "ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", - "dev": true - } } }, "random-poly-fill": { @@ -8350,6 +11515,11 @@ "resolved": "https://registry.npmjs.org/random-poly-fill/-/random-poly-fill-1.0.1.tgz", "integrity": "sha512-bMOL0hLfrNs52+EHtIPIXxn2PxYwXb0qjnKruTjXiM/sKfYqj506aB2plFwWW1HN+ri724bAVVGparh4AtlJKw==" }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, "raw-body": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", @@ -8373,24 +11543,38 @@ } }, "rc-config-loader": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-2.0.5.tgz", - "integrity": "sha512-T464K2MQlnNWOblUDIglpFhyN+zYJq7jSlL++/N0hUkcmIXeNFumwXFVdtf8qhUGohn4RYQ0wdi74R575I44PQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.0.0.tgz", + "integrity": "sha512-//LRTblJEcqbmmro1GCmZ39qZXD+JqzuD8Y5/IZU3Dhp3A1Yr0Xn68ks8MQ6qKfKvYCWDveUmRDKDA40c+sCXw==", "dev": true, "requires": { "debug": "^4.1.1", - "js-yaml": "^3.12.0", - "json5": "^2.1.0", - "object-assign": "^4.1.0", - "object-keys": "^1.0.12", - "path-exists": "^3.0.0", + "js-yaml": "^4.0.0", + "json5": "^2.1.2", "require-from-string": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "react-is": { - "version": "16.10.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz", - "integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, "read": { @@ -8402,6 +11586,16 @@ "mute-stream": "~0.0.4" } }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -8411,72 +11605,149 @@ "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + } } }, "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { - "find-up": "^3.0.0", + "find-up": "^2.0.0", "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "requires": { - "util.promisify": "^1.0.0" + "picomatch": "^2.2.1" } }, "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", "requires": { - "resolve": "^1.1.6" + "resolve": "^1.9.0" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==" + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "registry-auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", - "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", "dev": true, "requires": { - "rc": "^1.2.8", - "safe-buffer": "^5.0.1" + "rc": "^1.2.8" } }, "registry-url": { @@ -8488,16 +11759,20 @@ "rc": "^1.2.8" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + "remote-git-tags": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", + "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", + "dev": true }, "repeat-string": { "version": "1.6.1", @@ -8505,9 +11780,10 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -8516,7 +11792,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -8526,113 +11802,83 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - } - }, - "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "requires": { - "lodash": "^4.17.11" - } - }, - "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "requires": { - "request-promise-core": "1.1.2", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "requireg": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz", - "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==", - "dev": true, - "requires": { - "nested-error-stacks": "~2.0.1", - "rc": "~1.2.7", - "resolve": "~1.7.1" - }, - "dependencies": { - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } - } + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "requires": { + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "requires": { - "resolve-from": "^3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "resolve-from": "^5.0.0" } }, "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 - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" }, "responselike": { "version": "1.0.2", @@ -8643,154 +11889,125 @@ "lowercase-keys": "^1.0.0" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true }, "retry": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "requires": { - "is-promise": "^2.1.0" + "align-text": "^0.1.1" } }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { - "aproba": "^1.1.1" + "glob": "^7.1.3" } }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { - "tslib": "^1.9.0" + "queue-microtask": "^1.2.2" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "selectn": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/selectn/-/selectn-1.1.2.tgz", - "integrity": "sha1-/IrNkd8/RaywGJHGdzrlKYUdaxc=", + "sanitize-html": { + "version": "1.27.5", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.27.5.tgz", + "integrity": "sha512-M4M5iXDAUEcZKLXkmk90zSYWEtk5NH3JmojQxKxV371fnMh+x9t1rqdmXaGoyEHw3z/X/8vnFhKjGL5xFGOJ3A==", "requires": { - "brackets2dots": "^1.1.0", - "curry2": "^1.0.0", - "debug": "^2.5.2", - "dotsplit.js": "^1.0.3" + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15", + "parse-srcset": "^1.0.2", + "postcss": "^7.0.27" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", "requires": { - "ms": "2.0.0" + "domelementtype": "^2.0.1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } } } }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", "dev": true, "requires": { - "semver": "^5.0.3" + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "semver-utils": { @@ -8799,40 +12016,56 @@ "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", "dev": true }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "serialize-error": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz", - "integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", "requires": { - "type-fest": "^0.3.0" + "type-fest": "^0.20.2" + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" } }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "setprototypeof": { "version": "1.1.1", @@ -8843,7 +12076,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -8851,20 +12083,93 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true + "shins": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/shins/-/shins-2.6.0.tgz", + "integrity": "sha512-Y9asd1r6GshJDskRgwLZmd9xX+5DU+T2mZ+wpPT0nee0AbSLdiiSZahbcuXE5EIljsEmWSwHhduAmkbbQrAdlw==", + "requires": { + "call-me-maybe": "^1.0.1", + "cheerio": "^1.0.0-rc.2", + "chokidar": "^3.0.2", + "compression": "^1.6.2", + "ejs": "^2.5.1", + "express": "^4.15.5", + "highlight.js": "^10.0.2", + "markdown-it": "^10.0.0", + "markdown-it-attrs": "^1.2.1", + "markdown-it-emoji": "^1.4.0", + "markdown-it-lazy-headers": "^0.1.3", + "opn": "^5.2.0", + "sanitize-html": "^1.15.0", + "tiny-opts-parser": "0.0.3", + "uglify-js": "^2.7.4", + "yaml": "^1.9.2" + } + }, + "should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=" + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" }, "simple-swizzle": { "version": "0.2.2", @@ -8875,246 +12180,202 @@ } }, "sinon": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", - "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", - "requires": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" - } - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz", + "integrity": "sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "smart-buffer": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", - "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^7.1.2", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, "requires": { - "ms": "2.0.0" + "@sinonjs/commons": "^1.7.0" } }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "@sinonjs/samsam": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", + "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", + "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "nise": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", + "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", + "dev": true, "requires": { - "kind-of": "^6.0.0" + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^7.0.4", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" } }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, "requires": { - "kind-of": "^6.0.0" + "isarray": "0.0.1" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "has-flag": "^4.0.0" } } } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, "requires": { - "kind-of": "^3.2.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { - "is-buffer": "^1.1.5" + "color-name": "~1.1.4" } + }, + "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 } } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, "socks": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", - "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", "dev": true, "requires": { "ip": "^1.1.5", - "smart-buffer": "4.0.2" + "smart-buffer": "^4.1.0" } }, "socks-proxy-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz", + "integrity": "sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg==", "dev": true, "requires": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" }, "dependencies": { - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "es6-promisify": "^5.0.0" + "ms": "2.1.2" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "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==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, "spawn-please": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-0.3.0.tgz", - "integrity": "sha1-2zOOxM/2Orxp8dDgjO6euL69nRE=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-1.0.0.tgz", + "integrity": "sha512-Kz33ip6NRNKuyTRo3aDWyWxeGeM0ORDO552Fs6E1nj4pLWPkl37SrRtTnq+MEopVaqgmaO6bAvVS+v64BJ5M/A==", "dev": true }, "spawn-shell": { @@ -9138,10 +12399,35 @@ "os-shim": "^0.1.2" } }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -9149,15 +12435,15 @@ } }, "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -9165,17 +12451,26 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", "dev": true }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "readable-stream": "^3.0.0" } }, "sprintf-js": { @@ -9192,6 +12487,7 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -9205,12 +12501,12 @@ } }, "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", "dev": true, "requires": { - "figgy-pudding": "^3.5.1" + "minipass": "^3.1.1" } }, "stack-trace": { @@ -9219,137 +12515,503 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "standard": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/standard/-/standard-14.3.1.tgz", - "integrity": "sha512-TUQwU7znlZLfgKH1Zwn/D84FitWZkUTfbxSiz/vFx+4c9GV+clSfG/qLiLZOlcdyzhw3oF5/pZydNjbNDfHPEw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { - "eslint": "~6.4.0", - "eslint-config-standard": "14.1.0", - "eslint-config-standard-jsx": "8.1.0", - "eslint-plugin-import": "~2.18.0", - "eslint-plugin-node": "~10.0.0", - "eslint-plugin-promise": "~4.2.1", - "eslint-plugin-react": "~7.14.2", - "eslint-plugin-standard": "~4.0.0", - "standard-engine": "^12.0.0" + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "standard": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/standard/-/standard-16.0.4.tgz", + "integrity": "sha512-2AGI874RNClW4xUdM+bg1LRXVlYLzTNEkHmTG5mhyn45OhbgwA+6znowkOGYy+WMb5HRyELvtNy39kcdMQMcYQ==", + "dev": true, + "requires": { + "eslint": "~7.18.0", + "eslint-config-standard": "16.0.3", + "eslint-config-standard-jsx": "10.0.0", + "eslint-plugin-import": "~2.24.2", + "eslint-plugin-node": "~11.1.0", + "eslint-plugin-promise": "~5.1.0", + "eslint-plugin-react": "~7.25.1", + "standard-engine": "^14.0.1" }, "dependencies": { + "@eslint/eslintrc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.20", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "eslint": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz", - "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", - "esquery": "^1.0.1", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", + "levn": "^0.4.1", + "lodash": "^4.17.20", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" } }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "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 + }, + "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 + }, + "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 + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, "standard-engine": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-12.0.0.tgz", - "integrity": "sha512-gJIIRb0LpL7AHyGbN9+hJ4UJns37lxmNTnMGRLC8CFrzQ+oB/K60IQjKNgPBCB2VP60Ypm6f8DFXvhVWdBOO+g==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", + "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", "dev": true, "requires": { - "deglob": "^4.0.0", - "get-stdin": "^7.0.0", - "minimist": "^1.1.0", - "pkg-conf": "^3.1.0" - } - }, - "static-eval": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", - "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", - "requires": { - "escodegen": "^1.8.1" + "get-stdin": "^8.0.0", + "minimist": "^1.2.5", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "standard-version": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.3.1.tgz", + "integrity": "sha512-5qMxXw/FxLouC5nANyx/5RY1kiorJx9BppUso8gN07MG64q2uLRmrPb4KfXp3Ql4s/gxjZwZ89e0FwxeLubGww==", + "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "chalk": "^2.4.2", + "conventional-changelog": "3.1.24", + "conventional-changelog-config-spec": "2.1.0", + "conventional-changelog-conventionalcommits": "4.5.0", + "conventional-recommended-bump": "6.1.0", + "detect-indent": "^6.0.0", + "detect-newline": "^3.1.0", + "dotgitignore": "^2.1.0", + "figures": "^3.1.0", + "find-up": "^5.0.0", + "fs-access": "^1.0.1", + "git-semver-tags": "^4.0.0", + "semver": "^7.1.1", + "stringify-package": "^1.0.1", + "yargs": "^16.0.0" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "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 + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } } } @@ -9357,93 +13019,134 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "duplexer": "~0.1.1", + "through": "~2.3.4" } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" } } } }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" } }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", "requires": { - "safe-buffer": "~5.1.0" + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" } }, + "stringify-package": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", + "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==", + "dev": true + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -9453,146 +13156,237 @@ } }, "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "swagger-methods": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.8.tgz", - "integrity": "sha512-G6baCwuHA+C5jf4FNOrosE4XlmGsdjbOjdBK4yuiDDj/ro9uR4Srj3OR84oQMT8F3qKp00tYNv0YN730oTHPZA==" + "integrity": "sha512-G6baCwuHA+C5jf4FNOrosE4XlmGsdjbOjdBK4yuiDDj/ro9uR4Srj3OR84oQMT8F3qKp00tYNv0YN730oTHPZA==", + "dev": true }, "swagger-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-4.1.0.tgz", - "integrity": "sha512-XVa4cBnl33enMropuqwM2vJHqsDNZEK5Bl33e8OzbA4V7ZRd7XFxOtPzA59xg4Qaby4r5hJflfEknrmaTmzuIg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-3.4.2.tgz", + "integrity": "sha512-himpIkA50AjTvrgtz0PPbzwWoTjj3F3ye/y1PcW/514YEp1A3IhAcJFkkEu7b1zHnSIthnzxC8aTy+XZG0D+iA==", + "dev": true, "requires": { "call-me-maybe": "^1.0.1", - "debug": "^3.1.0", - "json-schema-ref-parser": "^5.0.3", - "ono": "^4.0.5", - "swagger-methods": "^1.0.4", + "debug": "^3.0.0", + "es6-promise": "^4.1.1", + "json-schema-ref-parser": "^1.4.1", + "ono": "^4.0.2", + "swagger-methods": "^1.0.0", "swagger-schema-official": "2.0.0-bab6bed", - "z-schema": "^3.19.1" + "z-schema": "^3.16.1" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "requires": { "ms": "^2.1.1" } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true } } }, "swagger-schema-official": { "version": "2.0.0-bab6bed", "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", - "integrity": "sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0=" + "integrity": "sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0=", + "dev": true }, - "swagmock": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/swagmock/-/swagmock-1.0.0.tgz", - "integrity": "sha1-NMybzhqtei/QNeynVoZbMT5GrsA=", - "dev": true, + "swagger2openapi": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-6.2.3.tgz", + "integrity": "sha512-cUUktzLpK69UwpMbcTzjMw2ns9RZChfxh56AHv6+hTx3StPOX2foZjPgds3HlJcINbxosYYBn/D3cG8nwcCWwQ==", "requires": { + "better-ajv-errors": "^0.6.1", "call-me-maybe": "^1.0.1", - "chance": "^1.0.3", - "moment": "^2.13.0", - "randexp": "^0.4.2", - "swagger-parser": "^3.4.1" + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.4.3", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^4.0.8", + "reftools": "^1.1.5", + "yaml": "^1.8.3", + "yargs": "^15.3.1" }, "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "ms": "^2.1.1" + "color-convert": "^2.0.1" } }, - "json-schema-ref-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-1.4.1.tgz", - "integrity": "sha1-wMLkOL8HlnI7AkUbrovH3Qs3/tA=", - "dev": true, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "requires": { - "call-me-maybe": "^1.0.1", - "debug": "^2.2.0", - "es6-promise": "^3.0.2", - "js-yaml": "^3.4.6", - "ono": "^2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "ono": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/ono/-/ono-2.2.5.tgz", - "integrity": "sha1-2vCUiLURdNp6fkJ136sxtDj/oOM=", - "dev": true - } + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "swagger-parser": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-3.4.2.tgz", - "integrity": "sha512-himpIkA50AjTvrgtz0PPbzwWoTjj3F3ye/y1PcW/514YEp1A3IhAcJFkkEu7b1zHnSIthnzxC8aTy+XZG0D+iA==", - "dev": true, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "requires": { - "call-me-maybe": "^1.0.1", - "debug": "^3.0.0", - "es6-promise": "^4.1.1", - "json-schema-ref-parser": "^1.4.1", - "ono": "^4.0.2", - "swagger-methods": "^1.0.0", - "swagger-schema-official": "2.0.0-bab6bed", - "z-schema": "^3.16.1" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, + "swagmock": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/swagmock/-/swagmock-1.0.0.tgz", + "integrity": "sha1-NMybzhqtei/QNeynVoZbMT5GrsA=", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "chance": "^1.0.3", + "moment": "^2.13.0", + "randexp": "^0.4.2", + "swagger-parser": "^3.4.1" + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -9600,142 +13394,89 @@ "dev": true }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } }, "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "dev": true, + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" } }, "tarn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-2.0.0.tgz", - "integrity": "sha512-7rNMCZd3s9bhQh47ksAQd92ADFcJUjjbyOvyFjNLwTPpGieFHMC84S+LOzw0fx1uh6hnDz/19r8CPMnIjJlMMA==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz", + "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==" }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", "dev": true, "requires": { - "execa": "^0.7.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" } }, "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" } }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -9748,25 +13489,23 @@ "dev": true }, "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "3" } }, "tildify": { @@ -9774,49 +13513,22 @@ "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } + "tiny-opts-parser": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tiny-opts-parser/-/tiny-opts-parser-0.0.3.tgz", + "integrity": "sha1-1sc6f65FiKa7Sh+mgbxmk3a+RRU=" }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "to-readable-stream": { "version": "1.0.0", @@ -9824,24 +13536,12 @@ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", "dev": true }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "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==", "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "toidentifier": { @@ -9858,28 +13558,20 @@ } }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "requires": { - "punycode": "^2.1.0" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "traceparent": { "version": "1.0.0", @@ -9889,21 +13581,56 @@ "random-poly-fill": "^1.0.1" } }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -9911,14 +13638,16 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true }, "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" } }, "type-detect": { @@ -9927,9 +13656,18 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==" + "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==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } }, "typedarray": { "version": "0.0.6", @@ -9937,53 +13675,55 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "uglify-js": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz", - "integrity": "sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g==", + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, - "optional": true, "requires": { - "commander": "~2.20.3", - "source-map": "~0.6.1" + "is-typedarray": "^1.0.0" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true }, - "union-value": { + "unbox-primitive": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" } }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, "unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -10003,87 +13743,134 @@ } }, "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "dev": true, "requires": { - "crypto-random-string": "^1.0.0" + "crypto-random-string": "^2.0.0" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, "update-notifier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", - "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", "dev": true, "requires": { - "boxen": "^3.0.0", - "chalk": "^2.0.1", - "configstore": "^4.0.0", + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", - "is-installed-globally": "^0.1.0", - "is-npm": "^3.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + "urijs": { + "version": "1.19.7", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.7.tgz", + "integrity": "sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==" }, "url-parse-lax": { "version": "3.0.0", @@ -10094,48 +13881,50 @@ "prepend-http": "^2.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true }, "uuid4": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/uuid4/-/uuid4-1.1.4.tgz", - "integrity": "sha512-Gr1q2k40LpF8CokcnQFjPDsdslzJbTCTBG5xQIEflUov431gFkY5KduiGIeKYAamkQnNn4IfdHJbLnl9Bib8TQ==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uuid4/-/uuid4-2.0.2.tgz", + "integrity": "sha512-TzsQS8sN1B2m9WojyNp0X/3JL8J2RScnrAJnooNPL6lq3lA02/XdoWysyUgI6rAif0DzkkWk51N6OggujPy2RA==" }, "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "v8-to-istanbul": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "dev": true, "requires": { - "homedir-polyfill": "^1.0.1" + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } }, "validate-npm-package-license": { @@ -10160,25 +13949,49 @@ "validator": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + } } }, "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dev": true, "requires": { - "browser-process-hrtime": "^0.1.2" + "xml-name-validator": "^3.0.0" } }, "walker": { @@ -10199,10 +14012,15 @@ "defaults": "^1.0.3" } }, + "web-streams-polyfill": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz", + "integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q==" + }, "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "whatwg-encoding": { "version": "1.0.5", @@ -10216,16 +14034,16 @@ "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "which": { @@ -10236,38 +14054,236 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, + "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, + "requires": { + "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" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "widdershins": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widdershins/-/widdershins-4.0.1.tgz", + "integrity": "sha512-y7TGynno+J/EqRPtUrpEuEjJUc1N2ajfP7R4sHU7Qg8I/VFHGavBxL7ZTeOAVmd1fhmY2wJIbpX2LMDWf37vVA==", + "requires": { + "dot": "^1.1.3", + "fast-safe-stringify": "^2.0.7", + "highlightjs": "^9.12.0", + "httpsnippet": "^1.19.0", + "jgexml": "^0.4.4", + "markdown-it": "^10.0.0", + "markdown-it-emoji": "^1.4.0", + "node-fetch": "^2.0.0", + "oas-resolver": "^2.3.1", + "oas-schema-walker": "^1.1.3", + "openapi-sampler": "^1.0.0-beta.15", + "reftools": "^1.1.0", + "swagger2openapi": "^6.0.1", + "urijs": "^1.19.0", + "yaml": "^1.8.3", + "yargs": "^12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "^2.1.1" + "string-width": "^1.0.2 || 2" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -10277,67 +14293,135 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } } } }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, "window-size": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", - "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" }, "winston": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", - "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", - "requires": { - "async": "^2.6.1", - "diagnostics": "^1.1.1", - "is-stream": "^1.1.0", - "logform": "^2.1.1", - "one-time": "0.0.4", - "readable-stream": "^3.1.1", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.3.0" + "winston-transport": "^4.4.0" + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" }, "dependencies": { "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" } } } }, - "winston-transport": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", - "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", - "requires": { - "readable-stream": "^2.3.6", - "triple-beam": "^1.2.0" - } + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true }, "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "wrappy": { @@ -10345,39 +14429,28 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "dev": true }, "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, "xml": { @@ -10392,6 +14465,12 @@ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -10399,58 +14478,220 @@ "dev": true }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", - "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", - "requires": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yargs-unparser": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.4.tgz", + "integrity": "sha512-QxEx9+qEr7jwVM4ngnk95+sKZ5QXm5gx0cL97LDby0SiC8HHoUK0LPBg475JwQcRCqIVfMD8SubCWp1dEgKuwQ==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "^5.3.1", + "decamelize": "^1.2.0", + "flat": "^5.0.2", + "is-plain-obj": "^1.1.0", + "yargs": "^14.2.3" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "yargs-parser": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, + "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 + }, "z-schema": { "version": "3.25.1", "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.25.1.tgz", "integrity": "sha512-7tDlwhrBG+oYFdXNOjILSurpfQyuVgkRe3hB2q8TEssamDHB7BbLWYkYO98nTn0FibfdFroFKDjndbgufAgS/Q==", + "dev": true, "requires": { "commander": "^2.7.1", "core-js": "^2.5.7", "lodash.get": "^4.0.0", "lodash.isequal": "^4.0.0", "validator": "^10.0.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + } } } } diff --git a/package.json b/package.json index 37c4c965..bab066b0 100644 --- a/package.json +++ b/package.json @@ -2,15 +2,18 @@ "name": "quoting-service", "description": "Quoting Service hosted by a scheme", "license": "Apache-2.0", - "version": "8.4.0-snapshot", - "author": "Modusbox", + "version": "12.1.0", + "author": "ModusBox", "contributors": [ - "James Bush ", "Georgi Georgiev ", "Henk Kodde ", + "James Bush ", "Miguel de Barros ", "Rajiv Mothilal ", - "Steven Oderayi " + "Sam Kummary ", + "Shashikant Hirugade ", + "Steven Oderayi ", + "Vassilis Barzokas " ], "repository": { "type": "git", @@ -29,79 +32,77 @@ "jest" ] }, - "jest": { - "collectCoverageFrom": [ - "**/src/handlers/**/*.js", - "src/data/database.js", - "**/src/model/**/*.js" - ], - "coverageThreshold": { - "global": { - "statements": 90, - "functions": 90, - "branches": 90, - "lines": 90 - } - }, - "testEnvironment": "node" - }, - "dependencies": { - "@hapi/good": "8.2.4", - "@hapi/hapi": "18.4.0", - "@mojaloop/central-services-error-handling": "8.3.0", - "@mojaloop/central-services-logger": "8.1.2", - "@mojaloop/central-services-shared": "8.4.1", - "@mojaloop/event-sdk": "8.3.0", - "@mojaloop/ml-number": "8.2.0", - "axios": "0.19.0", - "blipp": "4.0.1", - "eslint-config-standard": "14.1.0", - "good-console": "8.0.0", - "good-squeeze": "5.1.0", - "hapi-openapi": "1.2.4", - "json-rules-engine": "4.1.0", - "jsonpath": "^1.0.2", - "knex": "0.20.1", - "memory-cache": "0.2.0", - "mysql": "2.17.1", - "node-fetch": "2.6.0", - "rc": "1.2.8" - }, - "devDependencies": { - "eslint": "6.6.0", - "jest": "24.9.0", - "jest-junit": "9.0.0", - "npm-audit-resolver": "2.1.0", - "npm-check-updates": "3.2.0", - "pre-commit": "1.2.2", - "proxyquire": "2.1.3", - "sinon": "7.5.0", - "standard": "14.3.1", - "swagmock": "1.0.0" - }, "pre-commit": [ - "standard", + "lint", "dep:check", - "test" + "test:unit" ], "scripts": { - "start": "node src/server.js", - "test": "jest --testMatch '**/test/unit/**/*.test.js'", + "start": "node src/index.js", + "test": "npm run test:unit", + "test:unit": "jest --testMatch '**/test/unit/**/*.test.js'", "test:coverage": "jest --coverage --coverageThreshold='{}' --testMatch '**/test/unit/**/*.test.js'", "test:coverage-check": "jest --coverage --testMatch '**/test/unit/**/*.test.js'", "test:junit": "jest --reporters=default --reporters=jest-junit --testMatch '**/test/unit/**/*.test.js'", - "lint": "eslint .", + "lint": "npm run standard", + "lint:fix": "npm run standard:fix", "standard": "standard", + "standard:fix": "standard --fix", "regenerate": "yo swaggerize:test --framework hapi --apiPath './src/interface/swagger.json'", "build": "docker build -t quoting-service:local -f ./Dockerfile ../", "run": "docker run -p 3002:3002 --rm --link db:mysql quoting-service:local", "package-lock": "docker run --rm -it quoting-service:local cat package-lock.json > package-lock.json", "docker:up": "docker-compose -f docker-compose.yml -f docker-compose.base.yml up", "docker:stop": "docker-compose -f docker-compose.yml -f docker-compose.base.yml stop", - "audit:resolve": "SHELL=sh resolve-audit", - "audit:check": "SHELL=sh check-audit", + "audit:resolve": "SHELL=sh resolve-audit --production", + "audit:check": "SHELL=sh check-audit --production", "dep:check": "npx ncu -e 2", - "dep:update": "npx ncu -u" + "dep:update": "npx ncu -u", + "release": "standard-version --releaseCommitMessageFormat 'chore(release): {{currentTag}} [skip ci]'" + }, + "dependencies": { + "@hapi/good": "9.0.1", + "@hapi/hapi": "20.2.1", + "@hapi/inert": "6.0.4", + "@hapi/vision": "6.1.0", + "@mojaloop/central-services-error-handling": "11.3.0", + "@mojaloop/central-services-logger": "10.6.2", + "@mojaloop/central-services-metrics": "11.0.0", + "@mojaloop/central-services-shared": "14.0.0", + "@mojaloop/event-sdk": "10.7.1", + "@mojaloop/ml-number": "11.2.1", + "@mojaloop/sdk-standard-components": "15.13.0", + "ajv": "8.6.3", + "ajv-keywords": "5.0.0", + "axios": "0.23.0", + "blipp": "4.0.2", + "eslint-config-standard": "16.0.3", + "event-stream": "4.0.1", + "good-console": "8.0.0", + "good-squeeze": "5.1.0", + "joi": "17.4.2", + "json-rules-engine": "5.0.2", + "knex": "0.95.11", + "memory-cache": "0.2.0", + "minimist": "1.2.5", + "mysql": "2.18.1", + "node-fetch": "3.0.0", + "parse-strings-in-object": "2.0.0", + "rc": "1.2.8" + }, + "devDependencies": { + "eslint": "8.0.0", + "jest": "27.2.5", + "jest-junit": "13.0.0", + "npm-audit-resolver": "2.3.1", + "npm-check-updates": "11.8.5", + "nyc": "15.1.0", + "pre-commit": "1.2.2", + "proxyquire": "2.1.3", + "sinon": "11.1.2", + "standard": "16.0.4", + "standard-version": "9.3.1", + "swagmock": "1.0.0" }, "generator-swaggerize": { "version": "4.11.0" diff --git a/secrets/jwsSigningKey.key b/secrets/jwsSigningKey.key new file mode 100644 index 00000000..abd85780 --- /dev/null +++ b/secrets/jwsSigningKey.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAvs6EjaQYxTPI2dS+L6zJQhszHCP79huvCDPhy/BmTWI4350r +jWiclBC/joy7BUGJszIVv6rrwbeN9OORHXwW0XSjcCEeksdkAee9kGvx/A2UcUOs +QQ3A3IvoxJAv+HJSmCGeKsc2pMrelBtma54i1JBF6H+SwrcM0a+UVsADQXOzKuyi +RYnkCEhZYHXAk7hM3cARvhYydqUnPehFccjS8v6sNTRZnqJ7z/XT3EKYkfizcCkH +iV9elB/PGGzkFWLjHZVTC/+hK6WhFYGEktNbQfDuMA4mnZT37QZEL1PlhnFfjfnr +npjFjcFzKJ+hHRrHqA9FZlo6J9efnUn/VHVCsQIDAQABAoIBAC5eFUwuUm6ptOdq +kYUYYhgUcAkonXQjKhe+M+LRWqr3cYa1tP26LEK3BzXm8RPH52SKiUp4iK4covyd +yIf3vbvMsmLvSXS1y5HC9QgBk16DFk2n+lYct39g6IHL4Dxp27Rohv0ySA8n1Yr8 +VZlVZnVtUe+8ALgcr5rNJikmpCPlQ85QFExS8JpxYbbczbm/Q7qcQGdRkop5oFR6 +0Zaze7L2F2M1C6IVzUUJKr+TVY58uWqCEqhRDadStkQgw9QPq+PVza5fnTtlIakK +sSk1orJqONWpMY90wNOk/DasMIrQK4RFlkkDgTPjvWSPDRG/p/iRxO2jde5/oyCU +b24TraECgYEA90yIBp3/0BgKE6KPBZzlN8SuwXXH6A3HBXvcVNaNucO5zgXSJcYy +UT8iIUUd1bndfFOv3W8c6bkkeX5fkLm35bqM442m7r56PeugxIpRFPaj6IoTqe3y +9TCaatnOztDjCBEaNcIrJZUzHj6/yffr5pakTcsyBPhpywHGfBNeu9UCgYEAxYUm +bDJOK4NrkUFRGdN6KuWQ1MYrFxFChO9bmmxntt3ncC79qPojmTVCrajjarIBbv97 +v/D8PoSf4MKK9qDDdKqZ0dViYUyQm0rbWIxWfVT2fWdy5Xr34BLGkyiyuGam1XBy +XR76uNTjT+z8VIMkXv2mi/tW9XecGTWTx6BTpW0CgYEA6z8jOuA8RDFKDKmb0iQR +LL7t2tz3ALlydLYBv7al9WvKKcEByqtCnGUpS2rbWb/IgQd/CW80muVjXCuqLxts +Y53VfnX2sbACyzqFodFOFloVTBVlZUYU08ebbT+q6rRs8/SI8VC3CLZofUIF4dP0 +1VLCE7rS50WEJfiXXtpySM0CgYAuJf3kKZy57eqj9W7NaeuROjGshOBsc0vnY0Uz +v0A8KXx5aYE6ibbnhNofWOZJd21+UZLINbW5paL1EH8HQGhqSbHGpORnd0wR/Ftj +ROawQbmVcyYVF7XyVHCw0UFwdAtmsu8FcseBh7vUYLpTxJAq4XiYHBElKNz/xtTQ +P1VLwQKBgBZuwI0/s/VORrmvok27Wbkup9dDA3XlMccyK2osf31IcH7JY4uMw+9i +RYVjMjIsPtO1Gf71mRcFsWkQYYtZ6V5yrxiLRVq8iSRkOPm2iJtolSg1edOrlVS6 +xLPUjxxopeTkZbi4heszkkOn8MvzRznONCXjDt98FubgcAmEr+XA +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/data/bulkQuotes.js b/src/data/bulkQuotes.js index 330195b5..30621c99 100644 --- a/src/data/bulkQuotes.js +++ b/src/data/bulkQuotes.js @@ -29,9 +29,11 @@ * Georgi Georgiev -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ 'use strict' -var Mockgen = require('../../test/util/mockgen.js') +const Mockgen = require('../../test/util/mockgen.js') /** * Operations on /bulkQuotes */ diff --git a/src/data/bulkQuotes/{id}.js b/src/data/bulkQuotes/{id}.js index 27a90c06..52b805f4 100644 --- a/src/data/bulkQuotes/{id}.js +++ b/src/data/bulkQuotes/{id}.js @@ -29,9 +29,11 @@ * Georgi Georgiev -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ 'use strict' -var Mockgen = require('../../../test/util/mockgen.js') +const Mockgen = require('../../../test/util/mockgen.js') /** * Operations on /bulkQuotes/{id} */ diff --git a/src/data/bulkQuotes/{id}/error.js b/src/data/bulkQuotes/{id}/error.js index 76ea0447..63990727 100644 --- a/src/data/bulkQuotes/{id}/error.js +++ b/src/data/bulkQuotes/{id}/error.js @@ -29,9 +29,11 @@ * Georgi Georgiev -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ 'use strict' -var Mockgen = require('../../../../test/util/mockgen.js') +const Mockgen = require('../../../../test/util/mockgen.js') /** * Operations on /bulkQuotes/{id}/error */ diff --git a/src/data/cachedDatabase.js b/src/data/cachedDatabase.js index f7c99be8..d9f235db 100644 --- a/src/data/cachedDatabase.js +++ b/src/data/cachedDatabase.js @@ -35,6 +35,8 @@ const Database = require('./database.js') const Cache = require('memory-cache').Cache const ErrorHandler = require('@mojaloop/central-services-error-handling') +const { getStackOrInspect } = require('../lib/util') + const DEFAULT_TTL_SECONDS = 60 /** @@ -112,7 +114,7 @@ class CachedDatabase extends Database { return value } catch (err) { - this.writeLog(`Error in getCacheValue: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getCacheValue: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } diff --git a/src/data/database.js b/src/data/database.js index e665290b..defec62d 100644 --- a/src/data/database.js +++ b/src/data/database.js @@ -34,12 +34,15 @@ 'use strict' -const util = require('util') -const LOCAL_ENUM = require('../lib/enum') const Knex = require('knex') +const util = require('util') const Logger = require('@mojaloop/central-services-logger') const ErrorHandler = require('@mojaloop/central-services-error-handling') const MLNumber = require('@mojaloop/ml-number') +const Enum = require('@mojaloop/central-services-shared').Enum + +const LOCAL_ENUM = require('../lib/enum') +const { getStackOrInspect } = require('../lib/util') /** * Abstracts operations against the database @@ -55,7 +58,7 @@ class Database { * @returns {promise} */ async connect () { - this.queryBuilder = Knex(this.config.database) + this.queryBuilder = new Knex(this.config.database) return this } @@ -106,7 +109,7 @@ class Database { .select() return rows.map(r => JSON.parse(r.rule)) } catch (err) { - this.writeLog(`Error in getTransferRules: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getTransferRules: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -128,7 +131,7 @@ class Database { } return rows[0].transactionInitiatorTypeId } catch (err) { - this.writeLog(`Error in getInitiatorType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getInitiatorType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -150,7 +153,7 @@ class Database { } return rows[0].transactionInitiatorId } catch (err) { - this.writeLog(`Error in getInitiator: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getInitiator: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -172,7 +175,7 @@ class Database { } return rows[0].transactionScenarioId } catch (err) { - this.writeLog(`Error in getScenario: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getScenario: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -194,7 +197,7 @@ class Database { } return rows[0].transactionSubScenarioId } catch (err) { - this.writeLog(`Error in getSubScenario: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getSubScenario: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -216,7 +219,7 @@ class Database { } return rows[0].amountTypeId } catch (err) { - this.writeLog(`Error in getAmountType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getAmountType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -238,7 +241,7 @@ class Database { this.writeLog(`inserted new transactionReference in db: ${transactionReferenceId}`) return transactionReferenceId } catch (err) { - this.writeLog(`Error in createTransactionReference: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createTransactionReference: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -260,7 +263,7 @@ class Database { this.writeLog(`inserted new duplicate check in db for quoteId: ${quoteId}`) return quoteId } catch (err) { - this.writeLog(`Error in createQuoteDuplicateCheck: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuoteDuplicateCheck: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -283,7 +286,7 @@ class Database { this.writeLog(`inserted new response duplicate check in db for quote ${quoteId}, quoteResponseId: ${quoteResponseId}`) return quoteId } catch (err) { - this.writeLog(`Error in createQuoteUpdateDuplicateCheck: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuoteUpdateDuplicateCheck: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -306,7 +309,7 @@ class Database { return rows[0].partyTypeId } catch (err) { - this.writeLog(`Error in getPartyType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getPartyType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -329,7 +332,7 @@ class Database { return rows[0].partyIdentifierTypeId } catch (err) { - this.writeLog(`Error in getPartyIdentifierType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getPartyIdentifierType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -339,15 +342,20 @@ class Database { * * @returns {promise} - id of the participant */ - async getParticipant (participantName, participantType) { + async getParticipant (participantName, participantType, currencyId, ledgerAccountTypeId = Enum.Accounts.LedgerAccountType.POSITION) { try { const rows = await this.queryBuilder('participant') - .where({ - name: participantName, - isActive: 1 - }) - .select() - + .innerJoin('participantCurrency', 'participantCurrency.participantId', 'participant.participantId') + .where({ 'participant.name': participantName }) + .andWhere({ 'participantCurrency.currencyId': currencyId }) + .andWhere({ 'participantCurrency.ledgerAccountTypeId': ledgerAccountTypeId }) + .andWhere({ 'participantCurrency.isActive': true }) + .andWhere({ 'participant.isActive': true }) + .select( + 'participant.*', + 'participantCurrency.participantCurrencyId', + 'participantCurrency.currencyId' + ) if ((!rows) || rows.length < 1) { // active participant does not exist, this is an error if (participantType && participantType === LOCAL_ENUM.PAYEE_DFSP) { @@ -361,7 +369,7 @@ class Database { return rows[0].participantId } catch (err) { - this.writeLog(`Error in getPartyIdentifierType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getPartyIdentifierType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -387,7 +395,7 @@ class Database { return rows[0].transferParticipantRoleTypeId } catch (err) { - this.writeLog(`Error in getTransferParticipantRoleType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getTransferParticipantRoleType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -413,7 +421,7 @@ class Database { return rows[0].ledgerEntryTypeId } catch (err) { - this.writeLog(`Error in getLedgerEntryType: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getLedgerEntryType: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -451,7 +459,7 @@ class Database { const enumVals = await Promise.all([ this.getPartyType(partyType), this.getPartyIdentifierType(party.partyIdInfo.partyIdType), - this.getParticipant(party.partyIdInfo.fspId), + this.getParticipant(party.partyIdInfo.fspId, participantType, currency), this.getTransferParticipantRoleType(participantType), this.getLedgerEntryType(ledgerEntryType) ]) @@ -462,13 +470,9 @@ class Database { refs.transferParticipantRoleTypeId = enumVals[3] refs.ledgerEntryTypeId = enumVals[4] - // todo: possibly push this subIdType lookup onto the array that gets awaited async... - // otherwise requests that have a subIdType will be a little slower due to the extra wait time - // TODO: this will not work as the partyIdentifierType table only caters for the 8 main partyTypes - // discuss adding a partyIdSubType database table to perform this lookup against if (party.partyIdInfo.partySubIdOrType) { - // TODO: review method signature - refs.partySubIdOrTypeId = await this.getPartyIdentifierType(party.partyIdInfo.partySubIdOrType) + // subIdOrTypeId value need not be one in the partyIdentifierType list as per the specification. + refs.partySubIdOrTypeId = party.partyIdInfo.partySubIdOrType } // insert a new quote party @@ -509,10 +513,23 @@ class Database { const createdParty = await this.createParty(txn, quotePartyId, newParty) this.writeLog(`inserted new party in db: ${util.inspect(createdParty)}`) } + if (party.partyIdInfo.extensionList) { + const extensions = party.partyIdInfo.extensionList.extension + // we need to store personal info also + const quoteParty = await this.getTxnQuoteParty(txn, quoteId, partyType) + for (const extension of extensions) { + const newExtensions = { + key: extension.key, + value: extension.value + } + const createQuotePartyIdInfoExtension = await this.createQuotePartyIdInfoExtension(txn, newExtensions, quoteParty) + this.writeLog(`inserted new QuotePartyIdInfoExtension in db: ${util.inspect(createQuotePartyIdInfoExtension)}`) + } + } return quotePartyId } catch (err) { - this.writeLog(`Error in createQuoteParty: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuoteParty: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -533,7 +550,7 @@ class Database { return rows } catch (err) { - this.writeLog(`Error in getQuotePartyView: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuotePartyView: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -561,7 +578,7 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getQuoteView: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuoteView: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -575,7 +592,7 @@ class Database { try { const rows = await this.queryBuilder('quoteResponseView') .where({ - quoteId: quoteId + quoteId }) .select() @@ -589,7 +606,7 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getQuoteResponseView: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuoteResponseView: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -603,7 +620,7 @@ class Database { try { const newParty = { ...party, - quotePartyId: quotePartyId + quotePartyId } const res = await this.queryBuilder('party') @@ -613,7 +630,7 @@ class Database { newParty.partyId = res[0] return newParty } catch (err) { - this.writeLog(`Error in createParty: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createParty: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -646,7 +663,23 @@ class Database { this.writeLog(`inserted new quote in db: ${util.inspect(quote)}`) return quote.quoteId } catch (err) { - this.writeLog(`Error in createQuote: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuote: ${getStackOrInspect(err)}`) + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } + } + + async createQuotePartyIdInfoExtension (txn, extensionList, quoteParty) { + try { + await this.queryBuilder('quotePartyIdInfoExtension') + .transacting(txn) + .insert({ + quotePartyId: quoteParty.quotePartyId, + key: extensionList.key, + value: extensionList.value + }) + return true + } catch (err) { + this.writeLog(`Error in createQuotePartyIdInfoExtension: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -674,16 +707,40 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getQuoteParty: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuoteParty: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } + async getTxnQuoteParty (txn, quoteId, partyType) { + try { + const rows = await this.queryBuilder('quoteParty') + .transacting(txn) + .innerJoin('partyType', 'partyType.partyTypeId', 'quoteParty.partyTypeId') + .where('quoteParty.quoteId', quoteId) + .andWhere('partyType.name', partyType) + .select('quoteParty.*') + + if ((!rows) || rows.length < 1) { + return null + } + + if (rows.length > 1) { + throw ErrorHandler.Factory.createInternalServerFSPIOPError(`Expected 1 quoteParty row for quoteId ${quoteId} and partyType ${partyType} but got: ${util.inspect(rows)}`) + } + + return rows[0] + } catch (err) { + this.writeLog(`Error in getQuoteParty: ${getStackOrInspect(err)}`) + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } + } /** * Gets the specified endpoint for the specified quote party * * @returns {promise} - resolves to the endpoint base url */ + async getQuotePartyEndpoint (quoteId, endpointType, partyType) { try { const rows = await this.queryBuilder('participantEndpoint') @@ -703,7 +760,7 @@ class Database { return rows[0].value } catch (err) { - this.writeLog(`Error in getQuotePartyEndpoint: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuotePartyEndpoint: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -729,7 +786,7 @@ class Database { return rows[0].value } catch (err) { - this.writeLog(`Error in getParticipantEndpoint: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getParticipantEndpoint: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -753,7 +810,7 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getQuoteDuplicateCheck: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuoteDuplicateCheck: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -777,7 +834,7 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getQuoteResponseDuplicateCheck: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getQuoteResponseDuplicateCheck: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -801,7 +858,7 @@ class Database { return rows[0] } catch (err) { - this.writeLog(`Error in getTransactionReference: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in getTransactionReference: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -837,7 +894,7 @@ class Database { this.writeLog(`inserted new quoteResponse in db: ${util.inspect(newQuoteResponse)}`) return newQuoteResponse } catch (err) { - this.writeLog(`Error in createQuoteResponse: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuoteResponse: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -861,7 +918,7 @@ class Database { this.writeLog(`inserted new quoteResponseIlpPacket in db: ${util.inspect(res)}`) return res } catch (err) { - this.writeLog(`Error in createIlpPacket: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createIlpPacket: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -888,7 +945,7 @@ class Database { this.writeLog(`inserted new geoCode in db: ${util.inspect(newGeoCode)}`) return res } catch (err) { - this.writeLog(`Error in createGeoCode: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createGeoCode: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } @@ -915,7 +972,35 @@ class Database { this.writeLog(`inserted new quoteError in db: ${util.inspect(newError)}`) return res } catch (err) { - this.writeLog(`Error in createQuoteError: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in createQuoteError: ${getStackOrInspect(err)}`) + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } + } + + /** + * Creates quoteExtensions rows + * + * @returns {object} + * @param {Array[{object}]} extensions - array of extension objects with quoteId, key and value properties + */ + async createQuoteExtensions (txn, extensions, quoteId, transactionId = undefined, quoteResponseId = undefined) { + try { + const newExtensions = extensions.map(({ key, value }) => ({ + quoteId, + quoteResponseId, + transactionId, + key, + value + })) + + const res = await this.queryBuilder('quoteExtension') + .transacting(txn) + .insert(newExtensions) + + this.writeLog(`inserted new quoteExtensions in db: ${util.inspect(newExtensions)}`) + return res + } catch (err) { + this.writeLog(`Error in createQuoteExtensions: ${getStackOrInspect(err)}`) throw ErrorHandler.Factory.reformatFSPIOPError(err) } } diff --git a/src/data/quotes.js b/src/data/quotes.js index f1d39877..042f1080 100644 --- a/src/data/quotes.js +++ b/src/data/quotes.js @@ -30,8 +30,12 @@ -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ + 'use strict' -var Mockgen = require('../../test/util/mockgen.js') + +const Mockgen = require('../../test/util/mockgen.js') /** * Operations on /quotes */ diff --git a/src/data/quotes/{id}.js b/src/data/quotes/{id}.js index 26a457f7..416068cf 100644 --- a/src/data/quotes/{id}.js +++ b/src/data/quotes/{id}.js @@ -29,9 +29,11 @@ * Georgi Georgiev -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ 'use strict' -var Mockgen = require('../../../test/util/mockgen.js') +const Mockgen = require('../../../test/util/mockgen.js') /** * Operations on /quotes/{id} */ diff --git a/src/data/quotes/{id}/error.js b/src/data/quotes/{id}/error.js index 3e42b4d7..fd770bc2 100644 --- a/src/data/quotes/{id}/error.js +++ b/src/data/quotes/{id}/error.js @@ -29,9 +29,11 @@ * Georgi Georgiev -------------- ******/ +// Ignore coverage for this file as it is only a mock implementation for now +/* istanbul ignore file */ 'use strict' -var Mockgen = require('../../../../test/util/mockgen.js') +const Mockgen = require('../../../../test/util/mockgen.js') /** * Operations on /quotes/{id}/error */ diff --git a/src/handlers/bulkQuotes.js b/src/handlers/bulkQuotes.js index b4e1ce9c..04e93ec2 100644 --- a/src/handlers/bulkQuotes.js +++ b/src/handlers/bulkQuotes.js @@ -27,12 +27,18 @@ * Henk Kodde * Georgi Georgiev + * Rajiv Mothilal -------------- ******/ 'use strict' +const util = require('util') +const Enum = require('@mojaloop/central-services-shared').Enum const ErrorHandler = require('@mojaloop/central-services-error-handling') +const EventSdk = require('@mojaloop/event-sdk') +const LibUtil = require('../lib/util') +const BulkQuotesModel = require('../model/bulkQuotes') /** * Operations on /bulkQuotes @@ -45,7 +51,40 @@ module.exports = { * produces: application/json * responses: 202, 400, 401, 403, 404, 405, 406, 501, 503 */ - post: function BulkQuotes () { - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.NOT_IMPLEMENTED, 'Bulk quotes not implemented') + post: async function BulkQuotes (context, request, h) { + // log request + request.server.log(['info'], `got a POST /bulkQuotes request: ${util.inspect(request.payload)}`) + + // instantiate a new quote model + const model = new BulkQuotesModel({ + db: request.server.app.database, + requestId: request.info.id + }) + + // extract some things from the request we may need if we have to deal with an error e.g. the + // originator and quoteId + const bulkQuoteId = request.payload.bulkQuoteId + const fspiopSource = request.headers[Enum.Http.Headers.FSPIOP.SOURCE] + + const span = request.span + try { + const spanTags = LibUtil.getSpanTags(request, Enum.Events.Event.Type.BULK_QUOTE, Enum.Events.Event.Action.PREPARE) + span.setTags(spanTags) + await span.audit({ + headers: request.headers, + payload: request.payload + }, EventSdk.AuditEventAction.start) + + // call the quote request handler in the model + model.handleBulkQuoteRequest(request.headers, request.payload, span) + } catch (err) { + // something went wrong, use the model to handle the error in a sensible way + request.server.log(['error'], `ERROR - POST /bulkQuotes: ${LibUtil.getStackOrInspect(err)}`) + const fspiopError = ErrorHandler.ReformatFSPIOPError(err) + model.handleException(fspiopSource, bulkQuoteId, fspiopError, request.headers, span) + } finally { + // eslint-disable-next-line no-unsafe-finally + return h.response().code(Enum.Http.ReturnCodes.ACCEPTED.CODE) + } } } diff --git a/src/handlers/bulkQuotes/{id}.js b/src/handlers/bulkQuotes/{id}.js index de7fdf6a..4e29eb33 100644 --- a/src/handlers/bulkQuotes/{id}.js +++ b/src/handlers/bulkQuotes/{id}.js @@ -32,30 +32,97 @@ 'use strict' -const ErrorHandler = require('@mojaloop/central-services-error-handling') - +const util = require('util') +const Enum = require('@mojaloop/central-services-shared').Enum +const EventSdk = require('@mojaloop/event-sdk') +const LibUtil = require('../../lib/util') +const BulkQuotesModel = require('../../model/bulkQuotes.js') /** * Operations on /bulkQuotes/{id} */ module.exports = { /** - * summary: BulkQuotesById + * summary: getBulkQuotesById * description: The HTTP request GET /bulkQuotes/<id> is used to get information regarding an earlier created or requested bulk quote. The <id> in the URI should contain the bulkQuoteId that was used for the creation of the bulk quote. * parameters: Accept * produces: application/json * responses: 202, 400, 401, 403, 404, 405, 406, 501, 503 */ - get: function BulkQuotesById () { - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.NOT_IMPLEMENTED, 'Bulk quotes not implemented') + get: async function getBulkQuotesById (context, request, h) { + // log request + request.server.log(['info'], `got a GET /bulkQuotes/{id} request for bulkQuoteId ${request.params.id}`) + + // instantiate a new quote model + const model = new BulkQuotesModel({ + db: request.server.app.database, + requestId: request.info.id + }) + + // extract some things from the request we may need if we have to deal with an error e.g. the + // originator and quoteId + const bulkQuoteId = request.params.id + const fspiopSource = request.headers[Enum.Http.Headers.FSPIOP.SOURCE] + + const span = request.span + try { + const spanTags = LibUtil.getSpanTags(request, Enum.Events.Event.Type.BULK_QUOTE, Enum.Events.Event.Action.GET) + span.setTags(spanTags) + await span.audit({ + headers: request.headers, + payload: request.payload + }, EventSdk.AuditEventAction.start) + // call the model to re-forward the quote update to the correct party + // note that we do not check if our caller is the correct party, but we + // will send the callback to the correct party regardless. + model.handleBulkQuoteGet(request.headers, bulkQuoteId, span) + } catch (err) { + // something went wrong, use the model to handle the error in a sensible way + request.server.log(['error'], `ERROR - GET /bulkQuotes/{id}: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, bulkQuoteId, err, request.headers, span) + } finally { + // eslint-disable-next-line no-unsafe-finally + return h.response().code(Enum.Http.ReturnCodes.ACCEPTED.CODE) + } }, /** - * summary: BulkQuotesById + * summary: putBulkQuotesById * description: The callback PUT /bulkQuotes/<id> is used to inform the client of a requested or created bulk quote. The <id> in the URI should contain the bulkQuoteId that was used for the creation of the bulk quote, or the <id> that was used in the GET /bulkQuotes/<id>. * parameters: body, Content-Length * produces: application/json * responses: 200, 400, 401, 403, 404, 405, 406, 501, 503 */ - put: function BulkQuotesById1 () { - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.NOT_IMPLEMENTED, 'Bulk quotes not implemented') + put: async function putBulkQuotesById (context, request, h) { + // log request + request.server.log(['info'], `got a PUT /bulkQuotes/{id} request: ${util.inspect(request.payload)}`) + + // instantiate a new quote model + const model = new BulkQuotesModel({ + db: request.server.app.database, + requestId: request.info.id + }) + + // extract some things from the request we may need if we have to deal with an error e.g. the + // originator and quoteId + const bulkQuoteId = request.params.id + const fspiopSource = request.headers[Enum.Http.Headers.FSPIOP.SOURCE] + + const span = request.span + try { + const spanTags = LibUtil.getSpanTags(request, Enum.Events.Event.Type.BULK_QUOTE, Enum.Events.Event.Action.FULFIL) + span.setTags(spanTags) + await span.audit({ + headers: request.headers, + payload: request.payload + }, EventSdk.AuditEventAction.start) + // call the quote update handler in the model + model.handleBulkQuoteUpdate(request.headers, bulkQuoteId, request.payload, span) + } catch (err) { + // something went wrong, use the model to handle the error in a sensible way + request.server.log(['error'], `ERROR - PUT /bulkQuotes/{id}: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, bulkQuoteId, err, request.headers, span) + } finally { + // eslint-disable-next-line no-unsafe-finally + return h.response().code(Enum.Http.ReturnCodes.OK.CODE) + } } } diff --git a/src/handlers/bulkQuotes/{id}/error.js b/src/handlers/bulkQuotes/{id}/error.js index 64928dfe..8f3b63ed 100644 --- a/src/handlers/bulkQuotes/{id}/error.js +++ b/src/handlers/bulkQuotes/{id}/error.js @@ -32,8 +32,11 @@ 'use strict' -const ErrorHandler = require('@mojaloop/central-services-error-handling') - +const util = require('util') +const Enum = require('@mojaloop/central-services-shared').Enum +const EventSdk = require('@mojaloop/event-sdk') +const LibUtil = require('../../../lib/util') +const BulkQuotesModel = require('../../../model/bulkQuotes') /** * Operations on /bulkQuotes/{id}/error */ @@ -45,7 +48,38 @@ module.exports = { * produces: application/json * responses: 200, 400, 401, 403, 404, 405, 406, 501, 503 */ - put: function BulkQuotesErrorById () { - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.NOT_IMPLEMENTED, 'Bulk quotes not implemented') + put: async function BulkQuotesErrorById (context, request, h) { + // log request + request.server.log(['info'], `got a PUT /bulkQuotes/{id}/error request: ${util.inspect(request.payload)}`) + + // instantiate a new quote model + const model = new BulkQuotesModel({ + db: request.server.app.database, + requestId: request.info.id + }) + + // extract some things from the request we may need if we have to deal with an error e.g. the + // originator and quoteId + const bulkQuoteId = request.params.id + const fspiopSource = request.headers[Enum.Http.Headers.FSPIOP.SOURCE] + + const span = request.span + try { + const spanTags = LibUtil.getSpanTags(request, Enum.Events.Event.Type.BULK_QUOTE, Enum.Events.Event.Action.ABORT) + span.setTags(spanTags) + await span.audit({ + headers: request.headers, + payload: request.payload + }, EventSdk.AuditEventAction.start) + // call the quote error handler in the model + model.handleBulkQuoteError(request.headers, bulkQuoteId, request.payload.errorInformation, span) + } catch (err) { + // something went wrong, use the model to handle the error in a sensible way + request.server.log(['error'], `ERROR - PUT /bulkQuotes/{id}/error: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, bulkQuoteId, err, request.headers) + } finally { + // eslint-disable-next-line no-unsafe-finally + return h.response().code(Enum.Http.ReturnCodes.OK.CODE) + } } } diff --git a/src/handlers/health.js b/src/handlers/health.js index 1e450b9e..b83e1c60 100644 --- a/src/handlers/health.js +++ b/src/handlers/health.js @@ -34,6 +34,34 @@ const packageJson = require('../../package.json') const envConfig = new Config() +/** + * @function getSubServiceHealthDatastore + * + * @description + * Gets the health of the Datastore by ensuring the table is currently locked + * in a migration state. This implicity checks the connection with the database. + * + * @returns Promise The SubService health object for the broker + */ +const getSubServiceHealthDatastore = async (db) => { + let status = statusEnum.OK + + try { + const isLocked = await db.getIsMigrationLocked() + if (isLocked) { + status = statusEnum.DOWN + } + } catch (err) { + Logger.debug(`getSubServiceHealthDatastore failed with error ${err.message}.`) + status = statusEnum.DOWN + } + + return { + name: serviceName.datastore, + status + } +} + /** * Operations on /health */ @@ -45,48 +73,17 @@ module.exports = { * produces: application/json * responses: 200, 400, 401, 403, 404, 405, 406, 501, 503 */ - get: async (request, h) => { - let db - // lets check to see if we are NOT in simpleRoutingMode - if (!envConfig.simpleRoutingMode) { - // assign the db object - db = request.server.app.database - } - - // Create function to query DB health - /** - * @function getSubServiceHealthDatastore - * - * @description - * Gets the health of the Datastore by ensuring the table is currently locked - * in a migration state. This implicity checks the connection with the database. - * - * @returns Promise The SubService health object for the broker - */ - const getSubServiceHealthDatastore = async () => { - let status = statusEnum.OK - - try { - const isLocked = await db.getIsMigrationLocked() - if (isLocked) { - status = statusEnum.DOWN - } - } catch (err) { - Logger.debug(`getSubServiceHealthDatastore failed with error ${err.message}.`) - status = statusEnum.DOWN - } - - return { - name: serviceName.datastore, - status - } - } - - // lets check to see if we are running in simpleRoutingMode + get: async (context, request, h) => { + // Check to see if we are NOT in simpleRoutingMode let serviceHealthList = [] + // console.log('envConfig', envConfig) if (!envConfig.simpleRoutingMode) { + // assign the db object + /* istanbul ignore next */ + // ignoring coverage, since we can't test this anonymous function and its tests are covered + // elsewhere serviceHealthList = [ - getSubServiceHealthDatastore + async () => getSubServiceHealthDatastore(request.server.app.database) ] } @@ -107,5 +104,6 @@ module.exports = { // return response return h.response(healthCheckResponse).code(code) - } + }, + getSubServiceHealthDatastore } diff --git a/src/handlers/index.js b/src/handlers/index.js new file mode 100644 index 00000000..d2157d16 --- /dev/null +++ b/src/handlers/index.js @@ -0,0 +1,50 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + + * ModusBox + - Rajiv Mothilal + + -------------- + ******/ + +'use strict' + +const OpenapiBackend = require('@mojaloop/central-services-shared').Util.OpenapiBackend +const quotes = require('./quotes') +const quotesById = require('./quotes/{id}') +const quotesErrorByID = require('./quotes/{id}/error') +const health = require('./health') +const bulkQuotes = require('./bulkQuotes') +const bulkQuotesById = require('./bulkQuotes/{id}') +const bulkQuotesErrorById = require('./bulkQuotes/{id}/error') + +module.exports = { + HealthGet: health.get, + QuotesErrorByIDPut: quotesErrorByID.put, + QuotesByIdGet: quotesById.get, + QuotesByIdPut: quotesById.put, + QuotesPost: quotes.post, + BulkQuotesErrorByIdPut: bulkQuotesErrorById.put, + BulkQuotesByIdGet: bulkQuotesById.get, + BulkQuotesByIdPut: bulkQuotesById.put, + BulkQuotesPost: bulkQuotes.post, + validationFail: OpenapiBackend.validationFail, + notFound: OpenapiBackend.notFound, + methodNotAllowed: OpenapiBackend.methodNotAllowed +} diff --git a/src/handlers/quotes.js b/src/handlers/quotes.js index 639020b9..e381e72c 100644 --- a/src/handlers/quotes.js +++ b/src/handlers/quotes.js @@ -51,7 +51,7 @@ module.exports = { * produces: application/json * responses: 202, 400, 401, 403, 404, 405, 406, 501, 503 */ - post: async function Quotes (request, h) { + post: async function Quotes (context, request, h) { // log request request.server.log(['info'], `got a POST /quotes request: ${util.inspect(request.payload)}`) @@ -76,13 +76,12 @@ module.exports = { }, EventSdk.AuditEventAction.start) // call the quote request handler in the model - const result = await model.handleQuoteRequest(request.headers, request.payload, span) - request.server.log(['info'], `POST quote request succeeded and returned: ${util.inspect(result)}`) + model.handleQuoteRequest(request.headers, request.payload, span) } catch (err) { // something went wrong, use the model to handle the error in a sensible way - request.server.log(['error'], `ERROR - POST /quotes: ${err.stack || util.inspect(err)}`) + request.server.log(['error'], `ERROR - POST /quotes: ${LibUtil.getStackOrInspect(err)}`) const fspiopError = ErrorHandler.ReformatFSPIOPError(err) - await model.handleException(fspiopSource, quoteId, fspiopError, request.headers, span) + model.handleException(fspiopSource, quoteId, fspiopError, request.headers, span) } finally { // eslint-disable-next-line no-unsafe-finally return h.response().code(Enum.Http.ReturnCodes.ACCEPTED.CODE) diff --git a/src/handlers/quotes/{id}.js b/src/handlers/quotes/{id}.js index 0135509a..4406f12e 100644 --- a/src/handlers/quotes/{id}.js +++ b/src/handlers/quotes/{id}.js @@ -50,7 +50,7 @@ module.exports = { * produces: application/json * responses: 202, 400, 401, 403, 404, 405, 406, 501, 503 */ - get: async function getQuotesById (request, h) { + get: async function getQuotesById (context, request, h) { // log request request.server.log(['info'], `got a GET /quotes/{id} request for quoteId ${request.params.id}`) @@ -76,15 +76,14 @@ module.exports = { // call the model to re-forward the quote update to the correct party // note that we do not check if our caller is the correct party, but we // will send the callback to the correct party regardless. - const result = await model.handleQuoteGet(request.headers, quoteId, span) - request.server.log(['info'], `GET quotes/{id} request succeeded and returned: ${util.inspect(result)}`) + model.handleQuoteGet(request.headers, quoteId, span) } catch (err) { // something went wrong, use the model to handle the error in a sensible way - request.server.log(['error'], `ERROR - GET /quotes/{id}: ${err.stack || util.inspect(err)}`) - await model.handleException(fspiopSource, quoteId, err, request.headers, span) + request.server.log(['error'], `ERROR - GET /quotes/{id}: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, quoteId, err, request.headers, span) } finally { // eslint-disable-next-line no-unsafe-finally - return h.response().code(202) + return h.response().code(Enum.Http.ReturnCodes.ACCEPTED.CODE) } }, @@ -95,7 +94,7 @@ module.exports = { * produces: application/json * responses: 200, 400, 401, 403, 404, 405, 406, 501, 503 */ - put: async function putQuotesById (request, h) { + put: async function putQuotesById (context, request, h) { // log request request.server.log(['info'], `got a PUT /quotes/{id} request: ${util.inspect(request.payload)}`) @@ -119,15 +118,14 @@ module.exports = { payload: request.payload }, EventSdk.AuditEventAction.start) // call the quote update handler in the model - const result = await model.handleQuoteUpdate(request.headers, quoteId, request.payload, span) - request.server.log(['info'], `PUT quote request succeeded and returned: ${util.inspect(result)}`) + model.handleQuoteUpdate(request.headers, quoteId, request.payload, span) } catch (err) { // something went wrong, use the model to handle the error in a sensible way - request.server.log(['error'], `ERROR - PUT /quotes/{id}: ${err.stack || util.inspect(err)}`) - await model.handleException(fspiopSource, quoteId, err, request.headers, span) + request.server.log(['error'], `ERROR - PUT /quotes/{id}: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, quoteId, err, request.headers, span) } finally { // eslint-disable-next-line no-unsafe-finally - return h.response().code(202) + return h.response().code(Enum.Http.ReturnCodes.OK.CODE) } } } diff --git a/src/handlers/quotes/{id}/error.js b/src/handlers/quotes/{id}/error.js index 55a0a28a..d5766c77 100644 --- a/src/handlers/quotes/{id}/error.js +++ b/src/handlers/quotes/{id}/error.js @@ -50,7 +50,7 @@ module.exports = { * produces: application/json * responses: 200, 400, 401, 403, 404, 405, 406, 501, 503 */ - put: async function QuotesByIdAndError (request, h) { + put: async function QuotesByIdAndError (context, request, h) { // log request request.server.log(['info'], `got a PUT /quotes/{id}/error request: ${util.inspect(request.payload)}`) @@ -74,12 +74,11 @@ module.exports = { payload: request.payload }, EventSdk.AuditEventAction.start) // call the quote error handler in the model - const result = await model.handleQuoteError(request.headers, quoteId, request.payload.errorInformation, span) - request.server.log(['info'], `PUT quote error request succeeded and returned: ${util.inspect(result)}`) + model.handleQuoteError(request.headers, quoteId, request.payload.errorInformation, span) } catch (err) { // something went wrong, use the model to handle the error in a sensible way - request.server.log(['error'], `ERROR - PUT /quotes/{id}/error: ${err.stack || util.inspect(err)}`) - await model.handleException(fspiopSource, quoteId, err, request.headers) + request.server.log(['error'], `ERROR - PUT /quotes/{id}/error: ${LibUtil.getStackOrInspect(err)}`) + model.handleException(fspiopSource, quoteId, err, request.headers) } finally { // eslint-disable-next-line no-unsafe-finally return h.response().code(Enum.Http.ReturnCodes.OK.CODE) diff --git a/src/handlers/routes.js b/src/handlers/routes.js new file mode 100644 index 00000000..6df299c3 --- /dev/null +++ b/src/handlers/routes.js @@ -0,0 +1,133 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Steven Oderayi + -------------- + ******/ + +'use strict' + +/** + * Request handler + * + * @param {object} api OpenAPIBackend instance + * @param {object} req Request + * @param {object} h Response handle + */ +const handleRequest = (api, req, h) => api.handleRequest( + { + method: req.method, + path: req.path, + body: req.payload, + query: req.query, + headers: req.headers + }, req, h) + +/** + * Core API Routes + * + * @param {object} api OpenAPIBackend instance + */ +const APIRoutes = (api) => [ + { + method: 'PUT', + path: '/quotes/{id}/error', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'quotes', 'sampled'], + description: 'PUT Quote error by ID' + } + }, + { + method: 'GET', + path: '/quotes/{id}', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'quotes', 'sampled'], + description: 'GET Quote by ID' + } + }, + { + method: 'PUT', + path: '/quotes/{id}', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'quotes', 'sampled'], + description: 'PUT Quote error by ID' + } + }, + { + method: 'POST', + path: '/quotes', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'quotes', 'sampled'], + description: 'POST Quote' + } + }, + { + method: 'PUT', + path: '/bulkQuotes/{id}/error', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'bulkQuotes', 'sampled'], + description: 'PUT Bulk Quotes error by ID' + } + }, + { + method: 'GET', + path: '/bulkQuotes/{id}', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'bulkQuotes', 'sampled'], + description: 'GET Bulk Quotes by ID' + } + }, + { + method: 'PUT', + path: '/bulkQuotes/{id}', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'bulkQuotes', 'sampled'], + description: 'PUT Bulk Quotes by ID' + } + }, + { + method: 'POST', + path: '/bulkQuotes', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'bulkQuotes', 'sampled'], + description: 'POST Bulk Quotes' + } + }, + { + method: 'GET', + path: '/health', + handler: (req, h) => handleRequest(api, req, h), + config: { + tags: ['api', 'health'], + description: 'GET health' + } + } +] + +module.exports = { APIRoutes } diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..7ddaad89 --- /dev/null +++ b/src/index.js @@ -0,0 +1,39 @@ +// (C)2018 ModusBox Inc. +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Henk Kodde + - Matt Kingston + - Vassilis Barzokas + -------------- + ******/ +/* istanbul ignore file */ + +const server = require('./server') + +module.exports = server() diff --git a/src/interface/QuotingService-swagger.yaml b/src/interface/QuotingService-swagger.yaml new file mode 100644 index 00000000..b3b1db24 --- /dev/null +++ b/src/interface/QuotingService-swagger.yaml @@ -0,0 +1,1677 @@ +openapi: 3.0.1 +info: + title: Quoting related parts of Open API for FSP Interoperability (FSPIOP) (Implementation + Friendly Version) + description: Based on API Definition.docx updated on 2018-03-13 Version 1.0. Note + - The API supports a maximum size of 65536 bytes (64 Kilobytes) in the HTTP header. + license: + name: Open API for FSP Interoperability (FSPIOP) (Implementation Friendly Version) + version: "1.1" +servers: + - url: / +paths: + /quotes/{id}/error: + put: + tags: + - quotes + - sampled + summary: QuotesByIdAndError + description: If the server is unable to find or create a quote, or some other + processing error occurs, the error callback PUT /quotes//error is used. + The in the URI should contain the quoteId that was used for the creation + of the quote, or the that was used in the GET /quotes/. + operationId: QuotesErrorByIDPut + parameters: + - $ref: '#/components/parameters/ID' + - $ref: '#/components/parameters/Content-Length' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + x-examples: + application/json: + errorInformation: + errorCode: “5100” + errorDescription: “This is an error description” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationObject' + required: true + responses: + '200': + $ref: '#/components/responses/Response200' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /quotes/{id}: + parameters: + - $ref: '#/components/parameters/ID' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + get: + tags: + - quotes + - sampled + summary: QuotesById + description: The HTTP request GET /quotes/ is used to get information regarding + an earlier created or requested quote. The in the URI should contain + the quoteId that was used for the creation of the quote. + operationId: QuotesByIdGet + parameters: + - $ref: '#/components/parameters/Accept' + responses: + '202': + $ref: '#/components/responses/Response202' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + put: + tags: + - quotes + - sampled + summary: QuotesById + description: The callback PUT /quotes/ is used to inform the client of a + requested or created quote. The in the URI should contain the quoteId + that was used for the creation of the quote, or the that was used in + the GET /quotes/GET /quotes/. + operationId: QuotesByIdPut + parameters: + - $ref: '#/components/parameters/Content-Length' + x-examples: + application/json: + transferAmount: + currency: “USD” + amount: “124.45” + payeeReceiveAmount: + currency: “USD” + amount: “123.45” + payeeFspFee: + currency: “USD” + amount: “1.45” + payeeFspCommission: + currency: “USD” + amount: 0 + expiration: “2016-05-24T08:38:08.699-04:00” + geoCode: + latitude: “+45.4215” + longitude: “+75.6972” + ilpPacket: “AYIBgQAAAAAAAASwNGxldmVsb25lLmRmc3AxLm1lci45T2RTOF81MDdqUUZERmZlakgyOVc4bXFmNEpLMHlGTFGCAUBQU0svMS4wCk5vbmNlOiB1SXlweUYzY3pYSXBFdzVVc05TYWh3CkVuY3J5cHRpb246IG5vbmUKUGF5bWVudC1JZDogMTMyMzZhM2ItOGZhOC00MTYzLTg0NDctNGMzZWQzZGE5OGE3CgpDb250ZW50LUxlbmd0aDogMTM1CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbgpTZW5kZXItSWRlbnRpZmllcjogOTI4MDYzOTEKCiJ7XCJmZWVcIjowLFwidHJhbnNmZXJDb2RlXCI6XCJpbnZvaWNlXCIsXCJkZWJpdE5hbWVcIjpcImFsaWNlIGNvb3BlclwiLFwiY3JlZGl0TmFtZVwiOlwibWVyIGNoYW50XCIsXCJkZWJpdElkZW50aWZpZXJcIjpcIjkyODA2MzkxXCJ9IgA” + condition: f5sqb7tBTWPd5Y8BDFdMm9BJR_MNI4isf8p8n4D5pHA + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/QuotesIDPutResponse' + required: true + responses: + '200': + $ref: '#/components/responses/Response200' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /quotes: + post: + tags: + - quotes + - sampled + summary: Quotes + description: The HTTP request POST /quotes is used to request the creation of + a quote for the provided financial transaction in the server. + operationId: QuotesPost + parameters: + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/Content-Length' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + x-examples: + application/json: + quoteId: “b51ec534-ee48-4575-b6a9-ead2955b8069” + transactionId: “a8323bc6-c228-4df2-ae82-e5a997baf899” + transactionRequestId: “a8323bc6-c228-4df2-ae82-e5a997baf890” + payee: + partyIdInfo: + partyIdType: “PERSONAL_ID” + partyIdentifier: “16135551212” + partySubIdOrType: “DRIVING_LICENSE” + fspId: “1234” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + merchantClassificationCode: 4321 + name: “Justin Trudeau” + personalInfo: + complexName: + firstName: “Justin” + middleName: “Pierre” + lastName: “Trudeau” + dateOfBirth: “1971-12-25” + payer: + partyIdInfo: + partyIdType: “PERSONAL_ID” + partyIdentifier: “16135551212” + partySubIdOrType: “PASSPORT” + fspId: “1234” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + merchantClassificationCode: 1234 + name: “Donald Trump” + personalInfo: + complexName: + firstName: “Donald” + middleName: “John” + lastName: “Trump” + dateOfBirth: “1946-06-14” + amountType: SEND + amount: + currency: “USD” + amount: “123.45” + fees: + currency: “USD” + amount: “1.25” + transactionType: + scenario: “DEPOSIT” + subScenario: “locally defined sub-scenario” + initiator: “PAYEE” + initiatorType: “CONSUMER” + refundInfo: + originalTransactionId: “b51ec534-ee48-4575-b6a9-ead2955b8069” + refundReason: “free text indicating reason for the refund” + balanceOfPayments: “123” + geoCode: + latitude: “+45.4215” + longitude: “+75.6972” + note: “Free-text memo” + expiration: “2016-05-24T08:38:08.699-04:00” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/QuotesPostRequest' + required: true + responses: + '202': + $ref: '#/components/responses/Response202' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /bulkQuotes/{id}/error: + put: + tags: + - bulkQuotes + - sampled + summary: BulkQuotesErrorById + description: If the server is unable to find or create a bulk quote, or another + processing error occurs, the error callback PUT /bulkQuotes//error is + used. The in the URI should contain the bulkQuoteId that was used for + the creation of the bulk quote, or the that was used in the GET /bulkQuotes/. + operationId: BulkQuotesErrorByIdPut + parameters: + - $ref: '#/components/parameters/ID' + - $ref: '#/components/parameters/Content-Length' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + x-examples: + application/json: + errorInformation: + errorCode: “5100” + errorDescription: “This is an error description” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationObject' + required: true + responses: + '200': + $ref: '#/components/responses/Response200' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /bulkQuotes/{id}: + parameters: + - $ref: '#/components/parameters/ID' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + get: + tags: + - bulkQuotes + - sampled + summary: BulkQuotesById + description: The HTTP request GET /bulkQuotes/ is used to get information + regarding an earlier created or requested bulk quote. The in the URI + should contain the bulkQuoteId that was used for the creation of the bulk + quote. + operationId: BulkQuotesByIdGet + parameters: + - $ref: '#/components/parameters/Accept' + responses: + '202': + $ref: '#/components/responses/Response202' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + put: + tags: + - bulkQuotes + - sampled + summary: BulkQuotesById + description: The callback PUT /bulkQuotes/ is used to inform the client + of a requested or created bulk quote. The in the URI should contain the + bulkQuoteId that was used for the creation of the bulk quote, or the + that was used in the GET /bulkQuotes/. + operationId: BulkQuotesByIdPut + parameters: + - $ref: '#/components/parameters/Content-Length' + x-examples: + application/json: + individualQuoteResults: + - quoteId: b51ec534-ee48-4575-b6a9-ead2955b8069, + - receiveAmount: + currency: USD + amount: 123.45 + - payeeFspFee: + currency: USD + amount: 1.45 + - payeeFspCommission: + currency: USD + amount: 1.45 + - ilpPacket: AYIBgQAAAAAAAASwNGxldmVsb25lLmRmc3AxLm1lci45T2RTOF81MDdqUUZERmZlakgyOVc4bXFmNEpLMHlGTFGCAUBQU0svMS4wCk5vbmNlOiB1SXlweUYzY3pYSXBFdzVVc05TYWh3CkVuY3J5cHRpb246IG5vbmUKUGF5bWVudC1JZDogMTMyMzZhM2ItOGZhOC00MTYzLTg0NDctNGMzZWQzZGE5OGE3CgpDb250ZW50LUxlbmd0aDogMTM1CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbgpTZW5kZXItSWRlbnRpZmllcjogOTI4MDYzOTEKCiJ7XCJmZWVcIjowLFwidHJhbnNmZXJDb2RlXCI6XCJpbnZvaWNlXCIsXCJkZWJpdE5hbWVcIjpcImFsaWNlIGNvb3BlclwiLFwiY3JlZGl0TmFtZVwiOlwibWVyIGNoYW50XCIsXCJkZWJpdElkZW50aWZpZXJcIjpcIjkyODA2MzkxXCJ9IgA, + - condition: f5sqb7tBTWPd5Y8BDFdMm9BJR_MNI4isf8p8n4D5pHA, + - errorInformation: + errorCode: 5100 + errorDescription: This is an error description + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + expiration: “2016-05-24T08:38:08.699-04:00” + extensionList: + extension: + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + - “key”: “errorDescription” + “value”: “This is a more detailed error description” + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BulkQuotesIDPutResponse' + required: true + responses: + '200': + $ref: '#/components/responses/Response200' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /bulkQuotes: + post: + tags: + - bulkQuotes + - sampled + summary: BulkQuotes + description: The HTTP request POST /bulkQuotes is used to request the creation + of a bulk quote for the provided financial transactions in the server. + operationId: BulkQuotesPost + parameters: + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/Content-Length' + - $ref: '#/components/parameters/Content-Type' + - $ref: '#/components/parameters/Date' + - $ref: '#/components/parameters/X-Forwarded-For' + - $ref: '#/components/parameters/FSPIOP-Source' + - $ref: '#/components/parameters/FSPIOP-Destination' + - $ref: '#/components/parameters/FSPIOP-Encryption' + - $ref: '#/components/parameters/FSPIOP-Signature' + - $ref: '#/components/parameters/FSPIOP-URI' + - $ref: '#/components/parameters/FSPIOP-HTTP-Method' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BulkQuotesPostRequest' + required: true + responses: + '202': + $ref: '#/components/responses/Response202' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' + /health: + get: + tags: + - health + summary: Get Server + description: The HTTP request GET /health is used to return the current status + of the API. + operationId: HealthGet + responses: + '200': + $ref: '#/components/responses/ResponseHealth200' + '400': + $ref: '#/components/responses/ErrorResponse400' + '401': + $ref: '#/components/responses/ErrorResponse401' + '403': + $ref: '#/components/responses/ErrorResponse403' + '404': + $ref: '#/components/responses/ErrorResponse404' + '405': + $ref: '#/components/responses/ErrorResponse405' + '406': + $ref: '#/components/responses/ErrorResponse406' + '501': + $ref: '#/components/responses/ErrorResponse501' + '503': + $ref: '#/components/responses/ErrorResponse503' +components: + schemas: + Amount: + title: Amount + pattern: ^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[1-9])?$ + type: string + description: The API data type Amount is a JSON String in a canonical format + that is restricted by a regular expression for interoperability reasons. This + pattern does not allow any trailing zeroes at all, but allows an amount without + a minor currency unit. It also only allows four digits in the minor currency + unit; a negative value is not allowed. Using more than 18 digits in the major + currency unit is not allowed. + AmountType: + title: AmountType + type: string + description: Below are the allowed values for the enumeration AmountType - SEND + Amount the Payer would like to send, that is, the amount that should be withdrawn + from the Payer account including any fees. - RECEIVE Amount the Payer would + like the Payee to receive, that is, the amount that should be sent to the + receiver exclusive fees. + enum: + - SEND + - RECEIVE + BalanceOfPayments: + title: BalanceOfPayments + pattern: ^[1-9]\d{2}$ + type: string + description: (BopCode) The API data type BopCode is a JSON String of 3 characters, + consisting of digits only. Negative numbers are not allowed. A leading zero + is not allowed. https://www.imf.org/external/np/sta/bopcode/ + CorrelationId: + title: CorrelationId + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + description: Identifier that correlates all messages of the same sequence. The + API data type UUID (Universally Unique Identifier) is a JSON String in canonical + format, conforming to RFC 4122, that is restricted by a regular expression + for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal + symbols and 4 dashes (‘-‘). + Currency: + title: CurrencyEnum + maxLength: 3 + minLength: 3 + type: string + description: The currency codes defined in ISO 4217 as three-letter alphabetic + codes are used as the standard naming representation for currencies. + enum: + - AED + - AFN + - ALL + - AMD + - ANG + - AOA + - ARS + - AUD + - AWG + - AZN + - BAM + - BBD + - BDT + - BGN + - BHD + - BIF + - BMD + - BND + - BOB + - BRL + - BSD + - BTN + - BWP + - BYN + - BZD + - CAD + - CDF + - CHF + - CLP + - CNY + - COP + - CRC + - CUC + - CUP + - CVE + - CZK + - DJF + - DKK + - DOP + - DZD + - EGP + - ERN + - ETB + - EUR + - FJD + - FKP + - GBP + - GEL + - GGP + - GHS + - GIP + - GMD + - GNF + - GTQ + - GYD + - HKD + - HNL + - HRK + - HTG + - HUF + - IDR + - ILS + - IMP + - INR + - IQD + - IRR + - ISK + - JEP + - JMD + - JOD + - JPY + - KES + - KGS + - KHR + - KMF + - KPW + - KRW + - KWD + - KYD + - KZT + - LAK + - LBP + - LKR + - LRD + - LSL + - LYD + - MAD + - MDL + - MGA + - MKD + - MMK + - MNT + - MOP + - MRO + - MUR + - MVR + - MWK + - MXN + - MYR + - MZN + - NAD + - NGN + - NIO + - NOK + - NPR + - NZD + - OMR + - PAB + - PEN + - PGK + - PHP + - PKR + - PLN + - PYG + - QAR + - RON + - RSD + - RUB + - RWF + - SAR + - SBD + - SCR + - SDG + - SEK + - SGD + - SHP + - SLL + - SOS + - SPL + - SRD + - STD + - SVC + - SYP + - SZL + - THB + - TJS + - TMT + - TND + - TOP + - TRY + - TTD + - TVD + - TWD + - TZS + - UAH + - UGX + - USD + - UYU + - UZS + - VEF + - VND + - VUV + - WST + - XAF + - XCD + - XDR + - XOF + - XPF + - XTS + - XXX + - YER + - ZAR + - ZMW + - ZWD + Date: + title: Date + pattern: ^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)$ + type: string + description: The API data type Date is a JSON String in a lexical format that + is restricted by a regular expression for interoperability reasons. This format, + as specified in ISO 8601, contains a date only. A more readable version of + the format is yyyy-MM-dd. Examples - "1982-05-23", "1987-08-05” + DateOfBirth: + title: DateofBirth (type Date) + pattern: ^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)$ + type: string + description: Date of Birth of the Party. + DateTime: + title: DateTime + pattern: ^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:(\.\d{3}))(?:Z|[+-][01]\d:[0-5]\d)$ + type: string + description: The API data type DateTime is a JSON String in a lexical format + that is restricted by a regular expression for interoperability reasons. The + format is according to ISO 8601, expressed in a combined date, time and time + zone format. A more readable version of the format is yyyy-MM-ddTHH:mm:ss.SSS[-HH:MM]. + Examples - "2016-05-24T08:38:08.699-04:00", "2016-05-24T08:38:08.699Z" (where + Z indicates Zulu time zone, same as UTC). + ErrorCode: + title: ErrorCode + pattern: ^(10|20|3[0-4]|4[0-4]|5[0-4])[0-9]{2}$ + type: string + description: The API data type ErrorCode is a JSON String of four characters, + consisting of digits only. Negative numbers are not allowed. A leading zero + is not allowed. Each error code in the API is a four-digit number, for example, + 1234, where the first number (1 in the example) represents the high-level + error category, the second number (2 in the example) represents the low-level + error category, and the last two numbers (34 in the example) represents the + specific error. + ErrorDescription: + title: ErrorDescription + maxLength: 128 + minLength: 1 + type: string + description: Error description string. + ExtensionKey: + title: ExtensionKey + maxLength: 32 + minLength: 1 + type: string + description: Extension key. + ExtensionValue: + title: ExtensionValue + maxLength: 128 + minLength: 1 + type: string + description: Extension value. + FirstName: + title: FirstName + maxLength: 128 + minLength: 1 + pattern: '^(?!\s*$)[\p{L}\p{gc=Mark}\p{digit}\p{gc=Connector_Punctuation}\p{Join_Control} .,''-]{1,128}$' + type: string + description: First name of the Party (Name Type). + FspId: + title: FspId + maxLength: 32 + minLength: 1 + type: string + description: FSP identifier. + IlpCondition: + title: IlpCondition + maxLength: 48 + pattern: ^[A-Za-z0-9-_]{43}$ + type: string + description: Condition that must be attached to the transfer by the Payer. + IlpFulfilment: + title: IlpFulfilment + maxLength: 48 + pattern: ^[A-Za-z0-9-_]{43}$ + type: string + description: Fulfilment that must be attached to the transfer by the Payee. + IlpPacket: + title: IlpPacket + maxLength: 32768 + minLength: 1 + pattern: ^[A-Za-z0-9-_]+[=]{0,2}$ + type: string + description: Information for recipient (transport layer information). + LastName: + title: LastName + maxLength: 128 + minLength: 1 + pattern: '^(?!\s*$)[\p{L}\p{gc=Mark}\p{digit}\p{gc=Connector_Punctuation}\p{Join_Control} .,''-]{1,128}$' + type: string + description: Last name of the Party (Name Type). + Latitude: + title: Latitude + pattern: ^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,6})?))$ + type: string + description: The API data type Latitude is a JSON String in a lexical format + that is restricted by a regular expression for interoperability reasons. + Longitude: + title: Longitude + pattern: ^(\+|-)?(?:180(?:(?:\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\.[0-9]{1,6})?))$ + type: string + description: The API data type Longitude is a JSON String in a lexical format + that is restricted by a regular expression for interoperability reasons. + MerchantClassificationCode: + title: MerchantClassificationCode + pattern: ^[\d]{1,4}$ + type: string + description: A limited set of pre-defined numbers. This list would be a limited + set of numbers identifying a set of popular merchant types like School Fees, + Pubs and Restaurants, Groceries, etc. + MiddleName: + title: MiddleName + maxLength: 128 + minLength: 1 + pattern: '^(?!\s*$)[\p{L}\p{gc=Mark}\p{digit}\p{gc=Connector_Punctuation}\p{Join_Control} .,''-]{1,128}$' + type: string + description: Middle name of the Party (Name Type). + Note: + title: Note + maxLength: 128 + minLength: 1 + type: string + description: Memo assigned to transaction + PartyIdentifier: + title: PartyIdentifier + maxLength: 128 + minLength: 1 + type: string + description: Identifier of the Party. + PartyIdType: + title: PartyIdTypeEnum + type: string + description: Below are the allowed values for the enumeration - MSISDN An MSISDN + (Mobile Station International Subscriber Directory Number, that is, the phone + number) is used as reference to a participant. The MSISDN identifier should + be in international format according to the ITU-T E.164 standard. Optionally, + the MSISDN may be prefixed by a single plus sign, indicating the international + prefix. - EMAIL An email is used as reference to a participant. The format + of the email should be according to the informational RFC 3696. - PERSONAL_ID + A personal identifier is used as reference to a participant. Examples of personal + identification are passport number, birth certificate number, and national + registration number. The identifier number is added in the PartyIdentifier + element. The personal identifier type is added in the PartySubIdOrType element. + - BUSINESS A specific Business (for example, an organization or a company) + is used as reference to a participant. The BUSINESS identifier can be in any + format. To make a transaction connected to a specific username or bill number + in a Business, the PartySubIdOrType element should be used. - DEVICE A specific + device (for example, a POS or ATM) id connected to a specific business or + organization is used as reference to a Party. For referencing a specific device + under a specific business or organization, use the PartySubIdOrType element. + - ACCOUNT_ID A bank account number or FSP account id should be used as reference + to a participant. The ACCOUNT_ID identifier can be in any format, as formats + can greatly differ depending on country and FSP. - IBAN A bank account number + or FSP account id is used as reference to a participant. The IBAN identifier + can consist of up to 34 alphanumeric characters and should be entered without + whitespace. - ALIAS An alias is used as reference to a participant. The alias + should be created in the FSP as an alternative reference to an account owner. + Another example of an alias is a username in the FSP system. The ALIAS identifier + can be in any format. It is also possible to use the PartySubIdOrType element + for identifying an account under an Alias defined by the PartyIdentifier. + enum: + - MSISDN + - EMAIL + - PERSONAL_ID + - BUSINESS + - DEVICE + - ACCOUNT_ID + - IBAN + - ALIAS + PartyName: + title: PartyName + maxLength: 128 + minLength: 1 + type: string + description: Name of the Party. Could be a real name or a nickname. + PartySubIdOrType: + title: PartySubIdOrType + maxLength: 128 + minLength: 1 + type: string + description: Either a sub-identifier of a PartyIdentifier, or a sub-type of + the PartyIdType, normally a PersonalIdentifierType. + PersonalIdentifierType: + title: PersonalIdentifierType + type: string + description: Below are the allowed values for the enumeration - PASSPORT A passport + number is used as reference to a Party. - NATIONAL_REGISTRATION A national + registration number is used as reference to a Party. - DRIVING_LICENSE A driving + license is used as reference to a Party. - ALIEN_REGISTRATION An alien registration + number is used as reference to a Party. - NATIONAL_ID_CARD A national id card + number is used as reference to a Party. - EMPLOYER_ID A tax identification + number is used as reference to a Party. - TAX_ID_NUMBER A tax identification + number is used as reference to a Party. - SENIOR_CITIZENS_CARD A senior citizens + card number is used as reference to a Party. - MARRIAGE_CERTIFICATE A marriage + certificate number is used as reference to a Party. - HEALTH_CARD A health + card number is used as reference to a Party. - VOTERS_ID A voter’s identification + number is used as reference to a Party. - UNITED_NATIONS An UN (United Nations) + number is used as reference to a Party. - OTHER_ID Any other type of identification + type number is used as reference to a Party. + enum: + - PASSPORT + - NATIONAL_REGISTRATION + - DRIVING_LICENSE + - ALIEN_REGISTRATION + - NATIONAL_ID_CARD + - EMPLOYER_ID + - TAX_ID_NUMBER + - SENIOR_CITIZENS_CARD + - MARRIAGE_CERTIFICATE + - HEALTH_CARD + - VOTERS_ID + - UNITED_NATIONS + - OTHER_ID + QuoteId: + title: QuoteId + minLength: 1 + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + description: Quote Identifier. The API data type UUID (Universally Unique Identifier) + is a JSON String in canonical format, conforming to RFC 4122, that is restricted + by a regular expression for interoperability reasons. An UUID is always 36 + characters long, 32 hexadecimal symbols and 4 dashes (‘-‘). A minLength of + 1 has been specified due to the regex not being validated on empty strings, + this should be removed once the enjoi module has been fixed. + RefundReason: + title: RefundReason + maxLength: 128 + minLength: 1 + type: string + description: Reason for the refund. + TransactionId: + title: TransactionId + minLength: 1 + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + description: Transaction Identifier. The API data type UUID (Universally Unique + Identifier) is a JSON String in canonical format, conforming to RFC 4122, + that is restricted by a regular expression for interoperability reasons. An + UUID is always 36 characters long, 32 hexadecimal symbols and 4 dashes (‘-‘). + A minLength of 1 has been specified due to the regex not being validated on + empty strings, this should be removed once the enjoi module has been fixed. + TransactionInitiator: + title: TransactionInitiatorEnum + type: string + description: Below are the allowed values for the enumeration - PAYER Sender + of funds is initiating the transaction. The account to send from is either + owned by the Payer or is connected to the Payer in some way. - PAYEE Recipient + of the funds is initiating the transaction by sending a transaction request. + The Payer must approve the transaction, either automatically by a pre-generated + OTP or by pre-approval of the Payee, or by manually approving in his or her + own Device. + enum: + - PAYER + - PAYEE + TransactionInitiatorType: + title: TransactionInitiatorTypeEnum + type: string + description: Below are the allowed values for the enumeration - CONSUMER Consumer + is the initiator of the transaction. - AGENT Agent is the initiator of the + transaction. - BUSINESS Business is the initiator of the transaction. - DEVICE + Device is the initiator of the transaction. + enum: + - CONSUMER + - AGENT + - BUSINESS + - DEVICE + TransactionScenario: + title: TransactionScenarioEnum + type: string + description: Below are the allowed values for the enumeration - DEPOSIT Used + for performing a Cash-In (deposit) transaction. In a normal scenario, electronic + funds are transferred from a Business account to a Consumer account, and physical + cash is given from the Consumer to the Business User. - WITHDRAWAL Used for + performing a Cash-Out (withdrawal) transaction. In a normal scenario, electronic + funds are transferred from a Consumer’s account to a Business account, and + physical cash is given from the Business User to the Consumer. - TRANSFER + Used for performing a P2P (Peer to Peer, or Consumer to Consumer) transaction. + - PAYMENT Usually used for performing a transaction from a Consumer to a Merchant + or Organization, but could also be for a B2B (Business to Business) payment. + The transaction could be online for a purchase in an Internet store, in a + physical store where both the Consumer and Business User are present, a bill + payment, a donation, and so on. - REFUND Used for performing a refund of transaction. + enum: + - DEPOSIT + - WITHDRAWAL + - TRANSFER + - PAYMENT + - REFUND + TransactionSubScenario: + title: TransactionSubScenario + pattern: ^[A-Z_]{1,32}$ + type: string + description: Possible sub-scenario, defined locally within the scheme (UndefinedEnum + Type). + UndefinedEnum: + title: UndefinedEnum + pattern: ^[A-Z_]{1,32}$ + type: string + description: The API data type UndefinedEnum is a JSON String consisting of + 1 to 32 uppercase characters including an underscore character (_). + BulkQuotesPostRequest: + title: BulkQuotesPostRequest + required: + - bulkQuoteId + - individualQuotes + - payer + type: object + additionalProperties: false + properties: + bulkQuoteId: + $ref: '#/components/schemas/QuoteId' + payer: + $ref: '#/components/schemas/Party' + geoCode: + $ref: '#/components/schemas/GeoCode' + expiration: + $ref: '#/components/schemas/DateTime' + individualQuotes: + maxItems: 1000 + minItems: 1 + type: array + description: List of quotes elements. + items: + $ref: '#/components/schemas/IndividualQuote' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: POST /bulkQuotes object + BulkQuotesIDPutResponse: + title: BulkQuotesIDPutResponse + required: + - expiration + type: object + additionalProperties: false + properties: + individualQuoteResults: + maxItems: 1000 + type: array + description: Fees for each individual transaction, if any of them are charged + per transaction. + items: + $ref: '#/components/schemas/IndividualQuoteResult' + expiration: + $ref: '#/components/schemas/DateTime' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: PUT /bulkQuotes/{id} object + ErrorInformation: + title: ErrorInformation + required: + - errorCode + - errorDescription + type: object + properties: + errorCode: + $ref: '#/components/schemas/ErrorCode' + errorDescription: + $ref: '#/components/schemas/ErrorDescription' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: Data model for the complex type ErrorInformation. + ErrorInformationObject: + title: ErrorInformationObject + required: + - errorInformation + type: object + additionalProperties: false + properties: + errorInformation: + $ref: '#/components/schemas/ErrorInformation' + description: Data model for the complex type object that contains ErrorInformation. + ErrorInformationResponse: + title: ErrorInformationResponse + type: object + properties: + errorInformation: + $ref: '#/components/schemas/ErrorInformation' + description: Data model for the complex type object that contains an optional + element ErrorInformation used along with 4xx and 5xx responses. + Extension: + title: Extension + required: + - key + - value + type: object + properties: + key: + $ref: '#/components/schemas/ExtensionKey' + value: + $ref: '#/components/schemas/ExtensionValue' + description: Data model for the complex type Extension + ExtensionList: + title: ExtensionList + required: + - extension + type: object + properties: + extension: + maxItems: 16 + minItems: 1 + type: array + description: Number of Extension elements + items: + $ref: '#/components/schemas/Extension' + description: Data model for the complex type ExtensionList + GeoCode: + title: GeoCode + required: + - latitude + - longitude + type: object + properties: + latitude: + $ref: '#/components/schemas/Latitude' + longitude: + $ref: '#/components/schemas/Longitude' + description: Data model for the complex type GeoCode. Indicates the geographic + location from where the transaction was initiated. + IndividualQuote: + title: IndividualQuote + required: + - amount + - amountType + - payee + - quoteId + - transactionId + - transactionType + type: object + properties: + quoteId: + $ref: '#/components/schemas/QuoteId' + transactionId: + $ref: '#/components/schemas/TransactionId' + payee: + $ref: '#/components/schemas/Party' + amountType: + $ref: '#/components/schemas/AmountType' + amount: + $ref: '#/components/schemas/Money' + fees: + $ref: '#/components/schemas/Money' + transactionType: + $ref: '#/components/schemas/TransactionType' + note: + $ref: '#/components/schemas/Note' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: Data model for the complex type IndividualQuote. + IndividualQuoteResult: + title: IndividualQuoteResult + required: + - quoteId + type: object + properties: + quoteId: + $ref: '#/components/schemas/QuoteId' + payee: + $ref: '#/components/schemas/Party' + transferAmount: + $ref: '#/components/schemas/Money' + payeeReceiveAmount: + $ref: '#/components/schemas/Money' + payeeFspFee: + $ref: '#/components/schemas/Money' + payeeFspCommission: + $ref: '#/components/schemas/Money' + ilpPacket: + $ref: '#/components/schemas/IlpPacket' + condition: + $ref: '#/components/schemas/IlpCondition' + errorInformation: + $ref: '#/components/schemas/ErrorInformation' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: Data model for the complex type IndividualQuoteResult. + Money: + title: Money + required: + - amount + - currency + type: object + properties: + currency: + $ref: '#/components/schemas/Currency' + amount: + $ref: '#/components/schemas/Amount' + description: Data model for the complex type Money. + Party: + title: Party + required: + - partyIdInfo + type: object + properties: + partyIdInfo: + $ref: '#/components/schemas/PartyIdInfo' + merchantClassificationCode: + $ref: '#/components/schemas/MerchantClassificationCode' + name: + $ref: '#/components/schemas/PartyName' + personalInfo: + $ref: '#/components/schemas/PartyPersonalInfo' + description: Data model for the complex type Party. + PartyComplexName: + title: PartyComplexName + type: object + properties: + firstName: + $ref: '#/components/schemas/FirstName' + middleName: + $ref: '#/components/schemas/MiddleName' + lastName: + $ref: '#/components/schemas/LastName' + description: Data model for the complex type PartyComplexName. + PartyIdInfo: + title: PartyIdInfo + required: + - partyIdType + - partyIdentifier + type: object + properties: + partyIdType: + $ref: '#/components/schemas/PartyIdType' + partyIdentifier: + $ref: '#/components/schemas/PartyIdentifier' + partySubIdOrType: + $ref: '#/components/schemas/PartySubIdOrType' + fspId: + $ref: '#/components/schemas/FspId' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: Data model for the complex type PartyIdInfo. + PartyPersonalInfo: + title: PartyPersonalInfo + type: object + properties: + complexName: + $ref: '#/components/schemas/PartyComplexName' + dateOfBirth: + $ref: '#/components/schemas/DateOfBirth' + description: Data model for the complex type PartyPersonalInfo. + QuotesPostRequest: + title: QuotesPostRequest + required: + - amount + - amountType + - payee + - payer + - quoteId + - transactionId + - transactionType + type: object + additionalProperties: false + properties: + quoteId: + $ref: '#/components/schemas/QuoteId' + transactionId: + $ref: '#/components/schemas/TransactionId' + transactionRequestId: + $ref: '#/components/schemas/TransactionId' + payee: + $ref: '#/components/schemas/Party' + payer: + $ref: '#/components/schemas/Party' + amountType: + $ref: '#/components/schemas/AmountType' + amount: + $ref: '#/components/schemas/Money' + fees: + $ref: '#/components/schemas/Money' + transactionType: + $ref: '#/components/schemas/TransactionType' + geoCode: + $ref: '#/components/schemas/GeoCode' + note: + $ref: '#/components/schemas/Note' + expiration: + $ref: '#/components/schemas/DateTime' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: POST /quotes object + QuotesIDPutResponse: + title: QuotesIDPutResponse + required: + - condition + - expiration + - ilpPacket + - transferAmount + type: object + additionalProperties: false + properties: + transferAmount: + $ref: '#/components/schemas/Money' + payeeReceiveAmount: + $ref: '#/components/schemas/Money' + payeeFspFee: + $ref: '#/components/schemas/Money' + payeeFspCommission: + $ref: '#/components/schemas/Money' + expiration: + $ref: '#/components/schemas/DateTime' + geoCode: + $ref: '#/components/schemas/GeoCode' + ilpPacket: + $ref: '#/components/schemas/IlpPacket' + condition: + $ref: '#/components/schemas/IlpCondition' + extensionList: + $ref: '#/components/schemas/ExtensionList' + description: PUT /quotes/{id} object + Refund: + title: Refund + required: + - originalTransactionId + type: object + properties: + originalTransactionId: + $ref: '#/components/schemas/TransactionId' + refundReason: + $ref: '#/components/schemas/RefundReason' + description: Data model for the complex type Refund. + Status: + title: Status + type: object + properties: + status: + type: string + description: The return status, usually "OK" + description: Data model for the api status. + TransactionType: + title: TransactionType + required: + - initiator + - initiatorType + - scenario + type: object + properties: + scenario: + $ref: '#/components/schemas/TransactionScenario' + subScenario: + $ref: '#/components/schemas/TransactionSubScenario' + initiator: + $ref: '#/components/schemas/TransactionInitiator' + initiatorType: + $ref: '#/components/schemas/TransactionInitiatorType' + refundInfo: + $ref: '#/components/schemas/Refund' + balanceOfPayments: + $ref: '#/components/schemas/BalanceOfPayments' + description: Data model for the complex type TransactionType. + responses: + ErrorResponse400: + description: Bad Request - The application cannot process the request; for example, + due to malformed syntax or the payload exceeded size restrictions. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse401: + description: Unauthorized - The request requires authentication in order to + be processed. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse403: + description: Forbidden - The request was denied and will be denied in the future. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse404: + description: Not Found - The resource specified in the URI was not found. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse405: + description: Method Not Allowed - An unsupported HTTP method for the request + was used. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse406: + description: Not acceptable - The server is not capable of generating content + according to the Accept headers sent in the request. Used in the API to indicate + that the server does not support the version that the client is requesting. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse501: + description: Not Implemented - The server does not support the requested service. + The client should not retry. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + ErrorResponse503: + description: Service Unavailable - The server is currently unavailable to accept + any new service requests. This should be a temporary state, and the client + should retry within a reasonable time frame. + headers: + Content-Length: + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. + schema: + type: integer + Content-Type: + description: The Content-Type header indicates the specific version of the + API used to send the payload body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInformationResponse' + Response200: + description: OK + content: {} + Response202: + description: Accepted + content: {} + ResponseHealth200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + parameters: + Accept: + name: accept + in: header + description: The Accept header field indicates the version of the API the client + would like the server to use. + required: true + schema: + type: string + Content-Length: + name: content-length + in: header + description: The Content-Length header field indicates the anticipated size + of the payload body. Only sent if there is a body. Note - The API supports + a maximum size of 5242880 bytes (5 Megabytes) + schema: + type: integer + Content-Type: + name: content-type + in: header + description: The Content-Type header indicates the specific version of the API + used to send the payload body. + required: true + schema: + type: string + Date: + name: date + in: header + description: The Date header field indicates the date when the request was sent. + required: true + schema: + type: string + X-Forwarded-For: + name: x-forwarded-for + in: header + description: The X-Forwarded-For header field is an unofficially accepted standard + used for informational purposes of the originating client IP address, as a + request might pass multiple proxies, firewalls, and so on. Multiple X-Forwarded-For + values as in the example shown here should be expected and supported by implementers + of the API. Note - An alternative to X-Forwarded-For is defined in RFC 7239. + However, to this point RFC 7239 is less-used and supported than X-Forwarded-For. + schema: + type: string + FSPIOP-Source: + name: fspiop-source + in: header + description: The FSPIOP-Source header field is a non-HTTP standard field used + by the API for identifying the sender of the HTTP request. The field should + be set by the original sender of the request. Required for routing and signature + verification (see header field FSPIOP-Signature). + required: true + schema: + type: string + FSPIOP-Destination: + name: fspiop-destination + in: header + description: The FSPIOP-Destination header field is a non-HTTP standard field + used by the API for HTTP header based routing of requests and responses to + the destination. The field should be set by the original sender of the request + (if known), so that any entities between the client and the server do not + need to parse the payload for routing purposes. + required: true + schema: + type: string + FSPIOP-Encryption: + name: fspiop-encryption + in: header + description: The FSPIOP-Encryption header field is a non-HTTP standard field + used by the API for applying end-to-end encryption of the request. + schema: + type: string + FSPIOP-Signature: + name: fspiop-signature + in: header + description: The FSPIOP-Signature header field is a non-HTTP standard field + used by the API for applying an end-to-end request signature. + schema: + type: string + FSPIOP-URI: + name: fspiop-uri + in: header + description: The FSPIOP-URI header field is a non-HTTP standard field used by + the API for signature verification, should contain the service URI. Required + if signature verification is used, for more information see API Signature + document. + schema: + type: string + FSPIOP-HTTP-Method: + name: fspiop-http-method + in: header + description: The FSPIOP-HTTP-Method header field is a non-HTTP standard field + used by the API for signature verification, should contain the service HTTP + method. Required if signature verification is used, for more information see + API Signature document. + schema: + type: string + ID: + name: id + in: path + required: true + description: Common ID between the FSPs for the request objects, decided by + the Payer FSP. The ID should be reused for resends of the same request for + a transaction. A new ID should be generated for each new request for a transaction. + schema: + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + Type: + name: Type + in: path + required: true + schema: + type: string + SubId: + name: SubId + in: path + required: true + schema: + type: string diff --git a/src/interface/swagger.json b/src/interface/swagger.json index e4c890a3..beeac7af 100644 --- a/src/interface/swagger.json +++ b/src/interface/swagger.json @@ -1,9 +1,9 @@ { "swagger": "2.0", "info": { - "version": "1.0", - "title": "Quoting related parts of Open API for FSP Interoperability (FSPIOP) (Implementation Friendly Version)", - "description": "Based on API Definition.docx updated on 2018-03-13 Version 1.0. Note - The API supports a maximum size of 65536 bytes (64 Kilobytes) in the HTTP header.", + "version": "1.1", + "title": "Quoting related parts of Open API for FSP Interoperability (FSPIOP) API Version 1.1", + "description": "Based on API Definition.docx updated on 2020-05-19 Version 1.1. Note - The API supports a maximum size of 65536 bytes (64 Kilobytes) in the HTTP header.", "license": { "name": "Open API for FSP Interoperability (FSPIOP) (Implementation Friendly Version)" } @@ -420,7 +420,15 @@ "“partyIdType”": "“PERSONAL_ID”", "“partyIdentifier”": "“16135551212”", "“partySubIdOrType”": "“DRIVING_LICENSE”", - "“fspId”": "“1234”" + "“fspId”": "“1234”", + "“extensionList“": { + "“extension“": [ + { + "“key“": "Account Type", + "“value“": "Wallet" + } + ] + } }, "merchantClassificationCode": "4321", "“name”": "“Justin Trudeau”", @@ -438,7 +446,15 @@ "“partyIdType”": "“PERSONAL_ID”", "“partyIdentifier”": "“16135551212”", "“partySubIdOrType”": "“PASSPORT”", - "“fspId”": "“1234”" + "“fspId”": "“1234”", + "“extensionList“": { + "“extension“": [ + { + "“key“": "Account Type", + "“value“": "Wallet" + } + ] + } }, "merchantClassificationCode": "1234", "“name”": "“Donald Trump”", @@ -1295,6 +1311,8 @@ "XDR", "XOF", "XPF", + "XTS", + "XXX", "YER", "ZAR", "ZMW", @@ -1351,7 +1369,7 @@ "type": "string", "minLength": 1, "maxLength": 128, - "pattern": "^(?!\\s*$)[\\w .,'-]{1,128}$", + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", "description": "First name of the Party (Name Type)." }, "FspId": { @@ -1394,7 +1412,7 @@ "type": "string", "minLength": 1, "maxLength": 128, - "pattern": "^(?!\\s*$)[\\w .,'-]{1,128}$", + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", "description": "Last name of the Party (Name Type)." }, "Latitude": { @@ -1420,7 +1438,7 @@ "type": "string", "minLength": 1, "maxLength": 128, - "pattern": "^(?!\\s*$)[\\w .,'-]{1,128}$", + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", "description": "Middle name of the Party (Name Type)." }, "Name": { @@ -1501,8 +1519,9 @@ "QuoteId": { "title": "QuoteId", "type": "string", + "minLength": 1, "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Quote Identifier. The API data type UUID (Universally Unique Identifier) is a JSON String in canonical format, conforming to RFC 4122, that is restricted by a regular expression for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal symbols and 4 dashes (‘-‘)." + "description": "Quote Identifier. The API data type UUID (Universally Unique Identifier) is a JSON String in canonical format, conforming to RFC 4122, that is restricted by a regular expression for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal symbols and 4 dashes (‘-‘). A minLength of 1 has been specified due to the regex not being validated on empty strings, this should be removed once the enjoi module has been fixed." }, "QRCODE": { "title": "QRCODE", @@ -1527,8 +1546,9 @@ "TransactionId": { "title": "TransactionId", "type": "string", + "minLength": 1, "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Transaction Identifier. The API data type UUID (Universally Unique Identifier) is a JSON String in canonical format, conforming to RFC 4122, that is restricted by a regular expression for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal symbols and 4 dashes (‘-‘)." + "description": "Transaction Identifier. The API data type UUID (Universally Unique Identifier) is a JSON String in canonical format, conforming to RFC 4122, that is restricted by a regular expression for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal symbols and 4 dashes (‘-‘). A minLength of 1 has been specified due to the regex not being validated on empty strings, this should be removed once the enjoi module has been fixed." }, "TransactionInitiator": { "title": "TransactionInitiatorEnum", @@ -1794,7 +1814,8 @@ "properties": { "errorCode": { "type": "string", - "description": "Specific error number." + "description": "Specific error number.", + "pattern": "^(10|20|3[0-4]|4[0-4]|5[0-4])[0-9]{2}$" }, "errorDescription": { "type": "string", @@ -1877,11 +1898,11 @@ "description": "Data model for the complex type GeoCode. Indicates the geographic location from where the transaction was initiated.", "properties": { "latitude": { - "type": "string", + "$ref": "#/definitions/Latitude", "description": "Latitude of the Party." }, "longitude": { - "type": "string", + "$ref": "#/definitions/Longitude", "description": "Longitude of the Party." } }, @@ -2159,7 +2180,7 @@ "description": "Party Id type, id, sub id or type, and FSP Id." }, "merchantClassificationCode": { - "type": "string", + "$ref": "#/definitions/MerchantClassificationCode", "description": "Used in the context of Payee Information, where the Payee happens to be a merchant accepting merchant payments." }, "name": { @@ -2182,15 +2203,24 @@ "properties": { "firstName": { "type": "string", - "description": "Party’s first name." + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", + "description": "Party’s first name.", + "minLength": 1, + "maxLength": 128 }, "middleName": { "type": "string", - "description": "Party’s middle name." + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", + "description": "Party’s middle name.", + "minLength": 1, + "maxLength": 128 }, "lastName": { "type": "string", - "description": "Party’s last name." + "pattern": "^(?!\\s*$)[\\p{L}\\p{gc=Mark}\\p{digit}\\p{gc=Connector_Punctuation}\\p{Join_Control} .,''-]{1,128}$", + "description": "Party’s last name.", + "minLength": 1, + "maxLength": 128 } } }, @@ -2214,6 +2244,10 @@ "fspId": { "type": "string", "description": "FSP id (if known)" + }, + "extensionList": { + "$ref": "#/definitions/ExtensionList", + "description": "Optional extension, specific to deployment." } }, "required": [ @@ -2245,7 +2279,7 @@ "description": "First, middle and last name for the Party." }, "dateOfBirth": { - "type": "string", + "$ref": "#/definitions/DateOfBirth", "description": "Date of birth for the Party." } } @@ -2282,7 +2316,7 @@ "description": "Common id (decided by the Payer FSP) between the FSPs for the future transaction object. The actual transaction will be created as part of a successful transfer process. The id should be reused for resends of the same quote for a transaction. A new id should be generated for each new quote for a transaction." }, "transactionRequestId": { - "type": "string", + "$ref": "#/definitions/TransactionId", "description": "Identifies an optional previously-sent transaction request." }, "payee": { @@ -2294,7 +2328,7 @@ "description": "Information about the Payer in the proposed financial transaction." }, "amountType": { - "type": "string", + "$ref": "#/definitions/AmountType", "description": "SEND for send amount, RECEIVE for receive amount." }, "amount": { @@ -2318,7 +2352,7 @@ "description": "A memo that will be attached to the transaction." }, "expiration": { - "type": "string", + "$ref": "#/definitions/DateTime", "description": "Expiration is optional. It can be set to get a quick failure in case the peer FSP takes too long to respond. Also, it may be beneficial for Consumer, Agent, and Merchant to know that their request has a time limit." }, "extensionList": { @@ -2391,7 +2425,7 @@ "description": "Data model for the complex type Refund.", "properties": { "originalTransactionId": { - "type": "string", + "$ref": "#/definitions/TransactionId", "description": "Reference to the original transaction id that is requested to be refunded." }, "refundReason": { @@ -2515,19 +2549,19 @@ "description": "Data model for the complex type TransactionType.", "properties": { "scenario": { - "type": "string", + "$ref": "#/definitions/TransactionScenario", "description": "Deposit, withdrawal, refund, …" }, "subScenario": { - "type": "string", + "$ref": "#/definitions/TransactionSubScenario", "description": "Possible sub-scenario, defined locally within the scheme." }, "initiator": { - "type": "string", + "$ref": "#/definitions/TransactionInitiator", "description": "Who is initiating the transaction - Payer or Payee" }, "initiatorType": { - "type": "string", + "$ref": "#/definitions/TransactionInitiatorType", "description": "Consumer, agent, business, …" }, "refundInfo": { @@ -2535,7 +2569,7 @@ "description": "Extra information specific to a refund scenario. Should only be populated if scenario is REFUND" }, "balanceOfPayments": { - "type": "string", + "$ref": "#/definitions/BalanceOfPayments", "description": "Balance of Payments code." } }, @@ -2863,7 +2897,7 @@ "name": "fspiop-destination", "in": "header", "type": "string", - "required": false, + "required": true, "description": "The FSPIOP-Destination header field is a non-HTTP standard field used by the API for HTTP header based routing of requests and responses to the destination. The field should be set by the original sender of the request (if known), so that any entities between the client and the server do not need to parse the payload for routing purposes." }, "FSPIOP-Encryption": { @@ -2898,7 +2932,8 @@ "name": "id", "in": "path", "required": true, - "type": "string" + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" }, "Type": { "name": "Type", @@ -2913,4 +2948,4 @@ "type": "string" } } -} +} \ No newline at end of file diff --git a/src/lib/config.js b/src/lib/config.js index 2b23a199..30c4d4e2 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -30,12 +30,20 @@ -------------- ******/ -const RC = require('rc')('QUOTE', require('../../config/default.json')) +const RC = require('parse-strings-in-object')(require('rc')('QUOTE', require('../../config/default.json'))) +const fs = require('fs') /** * Loads config from environment */ class Config { + getFileContent (path) { + if (!fs.existsSync(path)) { + throw new Error(`File ${path} doesn't exist, can't enable JWS signing`) + } + return fs.readFileSync(path) + } + constructor () { // load config from environment (or use sensible defaults) this.listenAddress = RC.LISTEN_ADDRESS @@ -80,6 +88,13 @@ class Config { debug: RC.DATABASE.DEBUG ? RC.DATABASE.DEBUG : false } this.errorHandling = RC.ERROR_HANDLING + this.jws = { + jwsSign: RC.ENDPOINT_SECURITY.JWS.JWS_SIGN, + fspiopSourceToSign: RC.ENDPOINT_SECURITY.JWS.FSPIOP_SOURCE_TO_SIGN, + jwsSigningKeyPath: RC.ENDPOINT_SECURITY.JWS.JWS_SIGNING_KEY_PATH, + jwsSigningKey: RC.ENDPOINT_SECURITY.JWS.JWS_SIGN ? this.getFileContent(RC.ENDPOINT_SECURITY.JWS.JWS_SIGNING_KEY_PATH) : undefined + } + this.apiDocumentationEndpoints = RC.API_DOCUMENTATION_ENDPOINTS || false } } diff --git a/src/lib/http.js b/src/lib/http.js new file mode 100644 index 00000000..c50b8e28 --- /dev/null +++ b/src/lib/http.js @@ -0,0 +1,89 @@ +// (C)2018 ModusBox Inc. +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Henk Kodde + - Matt Kingston + - Vassilis Barzokas + -------------- + ******/ + +const axios = require('axios') +const util = require('util') +const ErrorHandler = require('@mojaloop/central-services-error-handling') + +const { getStackOrInspect } = require('../lib/util') + +// TODO: where httpRequest is called, there's a pretty common pattern of obtaining an endpoint from +// the database, specialising a template string with that endpoint, then calling httpRequest. Is +// there common functionality in these places than can reasonably be factored out? +/** + * Encapsulates making an HTTP request and translating any error response into a domain-specific + * error type. + * + * @param {Object} opts + * @param {String} fspiopSource + * @returns {Promise} + */ +async function httpRequest (opts, fspiopSource) { + // Network errors lob an exception. Bear in mind 3xx 4xx and 5xx are not network errors so we + // need to wrap the request below in a `try catch` to handle network errors + let res + let body + + try { + res = await axios.request(opts) + body = await res.data + } catch (e) { + const [fspiopErrorType, fspiopErrorDescr] = e.response && e.response.status === 404 + ? [ErrorHandler.Enums.FSPIOPErrorCodes.CLIENT_ERROR, 'Not found'] + : [ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, 'Network error'] + throw ErrorHandler.CreateFSPIOPError(fspiopErrorType, fspiopErrorDescr, + `${getStackOrInspect(e)}. Opts: ${util.inspect(opts)}`, + fspiopSource) + } + + // handle non network related errors below + if (res.status < 200 || res.status >= 300) { + const errObj = util.inspect({ + opts, + status: res.status, + statusText: res.statusText, + body + }) + + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, + 'Non-success response in HTTP request', + `${errObj}`, + fspiopSource) + } +} + +module.exports = { + httpRequest +} diff --git a/src/lib/util.js b/src/lib/util.js index e43dcaa6..589c054b 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -32,7 +32,18 @@ 'use strict' +const util = require('util') +const crypto = require('crypto') const Enum = require('@mojaloop/central-services-shared').Enum +const Logger = require('@mojaloop/central-services-logger') +const resourceVersions = require('@mojaloop/central-services-shared').Util.resourceVersions +const Config = require('./config') +const axios = require('axios') + +const failActionHandler = async (request, h, err) => { + Logger.error(`validation failure: ${getStackOrInspect}`) + throw err +} const getSpanTags = ({ payload, headers, params }, transactionType, transactionAction) => { const tags = { @@ -43,15 +54,172 @@ const getSpanTags = ({ payload, headers, params }, transactionType, transactionA source: headers[Enum.Http.Headers.FSPIOP.SOURCE], destination: headers[Enum.Http.Headers.FSPIOP.DESTINATION] } - if (payload && payload.payee && payload.payee.partyIdInfo && payload.payee.partyIdInfo.fspId) { - tags.payeeFsp = payload.payee.partyIdInfo.fspId + + const payeeFsp = getSafe(['payee', 'partyIdInfo', 'fspId'], payload) + const payerFsp = getSafe(['payer', 'partyIdInfo', 'fspId'], payload) + + if (payeeFsp) { + tags.payeeFsp = payeeFsp } - if (payload && payload.payer && payload.payer.partyIdInfo && payload.payer.partyIdInfo.fspId) { - tags.payerFsp = payload.payer.partyIdInfo.fspId + if (payerFsp) { + tags.payerFsp = payerFsp } + return tags } +/** + * @function getStackOrInspect + * @description Gets the error stack, or uses util.inspect to inspect the error + * @param {*} err - An error object + */ +function getStackOrInspect (err) { + return err.stack || util.inspect(err) +} + +/** + * @function getSafe + * @description Saftely get a nested value + * @param {Array} path - the path to the required variable + * @param {*} obj - The object with which to get the value from + * @returns {any | undefined} - The object at the path, or undefined + * + * @example + * Instead of the following: + * const fspId = payload && payload.payee && payload.payee.partyIdInfo && payload.payee.partyIdInfo.fspId + * + * You can use `getSafe()`: + * const fspId = getSafe(['payee', 'partyIdInfo', 'fspId'], payload) + * + */ +function getSafe (path, obj) { + return path.reduce((xs, x) => (xs && xs[x]) ? xs[x] : undefined, obj) +} + +/** + * Utility function to remove null and undefined keys from an object. + * This is useful for removing "nulls" that come back from database queries + * when projecting into API spec objects + * + * @returns {object} + */ +function removeEmptyKeys (originalObject) { + const obj = { ...originalObject } + Object.keys(obj).forEach(key => { + if (obj[key] && typeof obj[key] === 'object') { + if (Object.keys(obj[key]).length < 1) { + // remove empty object + delete obj[key] + } else { + // recurse + obj[key] = removeEmptyKeys(obj[key]) + } + } else if (obj[key] == null) { + // null or undefined, remove it + delete obj[key] + } + }) + return obj +} + +function applyResourceVersionHeaders (headers) { + let contentTypeHeader = headers['content-type'] || headers['Content-Type'] + let acceptHeader = headers.accept || headers.Accept + if (Enum.Http.Headers.FSPIOP.SWITCH.regex.test(headers['fspiop-source'])) { + if (Enum.Http.Headers.GENERAL.CONTENT_TYPE.regex.test(contentTypeHeader) && !!resourceVersions.quotes.contentVersion) { + contentTypeHeader = `application/vnd.interoperability.quotes+json;version=${resourceVersions.quotes.contentVersion}` + } + if (Enum.Http.Headers.GENERAL.ACCEPT.regex.test(acceptHeader) && !!resourceVersions.quotes.acceptVersion) { + acceptHeader = `application/vnd.interoperability.quotes+json;version=${resourceVersions.quotes.acceptVersion}` + } + } + return { contentTypeHeader, acceptHeader } +} + +/** + * Generates and returns an object containing API spec compliant HTTP request headers + * + * @returns {object} + */ +function generateRequestHeaders (headers, noAccept = false, additionalHeaders) { + const { contentTypeHeader, acceptHeader } = applyResourceVersionHeaders(headers) + let ret = { + 'Content-Type': contentTypeHeader, + Date: headers.date, + 'FSPIOP-Source': headers['fspiop-source'], + 'FSPIOP-Destination': headers['fspiop-destination'], + 'FSPIOP-HTTP-Method': headers['fspiop-http-method'], + 'FSPIOP-Signature': headers['fspiop-signature'], + 'FSPIOP-URI': headers['fspiop-uri'], + Accept: null + } + + if (!noAccept) { + ret.Accept = acceptHeader + } + // below are the non-standard headers added by the rules + if (additionalHeaders) { + ret = { ...ret, ...additionalHeaders } + } + + return removeEmptyKeys(ret) +} + +/** + * Generates and returns an object containing API spec compliant lowercase HTTP request headers for JWS Signing + * + * @returns {object} + */ +function generateRequestHeadersForJWS (headers, noAccept) { + const { contentTypeHeader, acceptHeader } = applyResourceVersionHeaders(headers) + const ret = { + 'Content-Type': contentTypeHeader, + date: headers.date, + 'fspiop-source': headers['fspiop-source'], + 'fspiop-destination': headers['fspiop-destination'], + 'fspiop-http-method': headers['fspiop-http-method'], + 'fspiop-signature': headers['fspiop-signature'], + 'fspiop-uri': headers['fspiop-uri'], + Accept: null + } + + if (!noAccept) { + ret.Accept = acceptHeader + } + + return removeEmptyKeys(ret) +} + +/** + * Returns the SHA-256 hash of the supplied request object + * + * @returns {undefined} + */ +function calculateRequestHash (request) { + // calculate a SHA-256 of the request + const requestStr = JSON.stringify(request) + return crypto.createHash('sha256').update(requestStr).digest('hex') +} + +const fetchParticipantInfo = async (source, destination) => { + // Get quote participants from central ledger admin + const { switchEndpoint } = new Config() + const url = `${switchEndpoint}/participants` + const [payer, payee] = await Promise.all([ + axios.request({ url: `${url}/${source}` }), + axios.request({ url: `${url}/${destination}` }) + ]) + return { payer: payer.data, payee: payee.data } +} + module.exports = { - getSpanTags + failActionHandler, + getSafe, + getSpanTags, + getStackOrInspect, + generateRequestHeaders, + generateRequestHeadersForJWS, + calculateRequestHash, + removeEmptyKeys, + fetchParticipantInfo } diff --git a/src/model/bulkQuotes.js b/src/model/bulkQuotes.js new file mode 100644 index 00000000..29ebc84c --- /dev/null +++ b/src/model/bulkQuotes.js @@ -0,0 +1,501 @@ +// (C)2018 ModusBox Inc. +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Rajiv Mothilal + -------------- + ******/ + +const axios = require('axios') +const util = require('util') + +const ENUM = require('@mojaloop/central-services-shared').Enum +const ErrorHandler = require('@mojaloop/central-services-error-handling') +const EventSdk = require('@mojaloop/event-sdk') +const LibUtil = require('@mojaloop/central-services-shared').Util +const Logger = require('@mojaloop/central-services-logger') +const JwsSigner = require('@mojaloop/sdk-standard-components').Jws.signer + +const Config = require('../lib/config') +const { httpRequest } = require('../lib/http') +const { getStackOrInspect, generateRequestHeadersForJWS, generateRequestHeaders } = require('../lib/util') +const LOCAL_ENUM = require('../lib/enum') + +delete axios.defaults.headers.common.Accept +delete axios.defaults.headers.common['Content-Type'] + +/** + * Encapsulates operations on the bulkQuotes domain model + * + * @returns {undefined} + */ + +class BulkQuotesModel { + constructor (config) { + this.config = config + this.db = config.db + this.requestId = config.requestId + } + + /** + * Validates the quote request object + * + * @returns {promise} - promise will reject if request is not valid + */ + async validateBulkQuoteRequest (fspiopSource, fspiopDestination, bulkQuoteRequest) { + await this.db.getParticipant(fspiopSource, LOCAL_ENUM.PAYER_DFSP, bulkQuoteRequest.individualQuotes[0].amount.currency, ENUM.Accounts.LedgerAccountType.POSITION) + await this.db.getParticipant(fspiopDestination, LOCAL_ENUM.PAYEE_DFSP, bulkQuoteRequest.individualQuotes[0].amount.currency, ENUM.Accounts.LedgerAccountType.POSITION) + } + + /** + * Logic for creating and handling quote requests + * + * @returns {object} - returns object containing keys for created database entities + */ + async handleBulkQuoteRequest (headers, bulkQuoteRequest, span) { + // accumulate enum ids + const refs = {} + let fspiopSource + let childSpan + try { + fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const fspiopDestination = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + + // validate - this will throw if the request is invalid + childSpan = span.getChild('qs_bulkquote_forwardBulkQuoteRequest') + await this.validateBulkQuoteRequest(fspiopSource, fspiopDestination, bulkQuoteRequest) + // if we got here rules passed, so we can forward the quote on to the recipient dfsp + await childSpan.audit({ headers, payload: bulkQuoteRequest }, EventSdk.AuditEventAction.start) + await this.forwardBulkQuoteRequest(headers, bulkQuoteRequest.bulkQuoteId, bulkQuoteRequest, childSpan) + } catch (err) { + // any-error + // as we are on our own in this context, dont just rethrow the error, instead... + // get the model to handle it + this.writeLog(`Error forwarding quote request: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) + await this.handleException(fspiopSource, bulkQuoteRequest.bulkQuoteId, err, headers, childSpan) + } finally { + if (childSpan && !childSpan.isFinished) { + await childSpan.finish() + } + } + + // all ok, return refs + return refs + } + + /** + * Forwards a quote request to a payee DFSP for processing + * + * @returns {undefined} + */ + async forwardBulkQuoteRequest (headers, bulkQuoteId, originalBulkQuoteRequest, span) { + let endpoint + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + + try { + // lookup payee dfsp callback endpoint + // TODO: for MVP we assume initiator is always payer dfsp! this may not always be the + // case if a xfer is requested by payee + endpoint = await this.db.getParticipantEndpoint(fspiopDest, ENUM.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_BULK_QUOTES) + + this.writeLog(`Resolved FSPIOP_CALLBACK_URL_BULK_QUOTES endpoint for bulkQuote ${bulkQuoteId} to: ${util.inspect(endpoint)}`) + + if (!endpoint) { + // internal-error + // we didnt get an endpoint for the payee dfsp! + // make an error callback to the initiator + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, `No FSPIOP_CALLBACK_URL_BULK_QUOTES found for quote ${bulkQuoteId} PAYEE party`, null, fspiopSource) + } + + const fullCallbackUrl = `${endpoint}${ENUM.EndPoints.FspEndpointTemplates.BULK_QUOTES_POST}` + const newHeaders = generateRequestHeaders(headers) + + this.writeLog(`Forwarding quote request to endpoint: ${fullCallbackUrl}`) + this.writeLog(`Forwarding quote request headers: ${JSON.stringify(newHeaders)}`) + this.writeLog(`Forwarding quote request body: ${JSON.stringify(originalBulkQuoteRequest)}`) + + let opts = { + method: ENUM.Http.RestMethods.POST, + url: fullCallbackUrl, + data: JSON.stringify(originalBulkQuoteRequest), + headers: newHeaders + } + + if (span) { + opts = span.injectContextToHttpRequest(opts) + span.audit(opts, EventSdk.AuditEventAction.egress) + } + + this.writeLog(`Forwarding request : ${util.inspect(opts)}`) + await httpRequest(opts, fspiopSource) + } catch (err) { + // any-error + this.writeLog(`Error forwarding bulkQuote request to endpoint ${endpoint}: ${getStackOrInspect(err)}`) + throw ErrorHandler.ReformatFSPIOPError(err) + } + } + + /** + * Logic for handling quote update requests e.g. PUT /bulkQuotes/{id} requests + * + * @returns {object} - object containing updated entities + */ + async handleBulkQuoteUpdate (headers, bulkQuoteId, bulkQuoteUpdateRequest, span) { + // ensure no 'accept' header is present in the request headers. + if ('accept' in headers) { + // internal-error + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, + `Update for bulk quote ${bulkQuoteId} failed: "accept" header should not be sent in callbacks.`, null, headers['fspiop-source']) + } + // if we got here rules passed, so we can forward the quote on to the recipient dfsp + const childSpan = span.getChild('qs_quote_forwardBulkQuoteUpdate') + try { + await childSpan.audit({ headers, params: { bulkQuoteId }, payload: bulkQuoteUpdateRequest }, EventSdk.AuditEventAction.start) + await this.forwardBulkQuoteUpdate(headers, bulkQuoteId, bulkQuoteUpdateRequest, childSpan) + } catch (err) { + // any-error + // as we are on our own in this context, dont just rethrow the error, instead... + // get the model to handle it + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + this.writeLog(`Error forwarding bulk quote update: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) + await this.handleException(fspiopSource, bulkQuoteId, err, headers, childSpan) + } finally { + if (childSpan && !childSpan.isFinished) { + await childSpan.finish() + } + } + } + + /** + * Forwards a bulk quote response to a payer DFSP for processing + * + * @returns {undefined} + */ + async forwardBulkQuoteUpdate (headers, bulkQuoteId, originalBulkQuoteResponse, span) { + let endpoint = null + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + + try { + // lookup payer dfsp callback endpoint + endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_BULK_QUOTES') + this.writeLog(`Resolved PAYER party FSPIOP_CALLBACK_URL_BULK_QUOTES endpoint for bulk quote ${bulkQuoteId} to: ${util.inspect(endpoint)}`) + + if (!endpoint) { + // we didnt get an endpoint for the payee dfsp! + // make an error callback to the initiator + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, `No FSPIOP_CALLBACK_URL_BULK_QUOTES found for quote ${bulkQuoteId} PAYER party`, null, fspiopSource) + return this.sendErrorCallback(fspiopSource, fspiopError, bulkQuoteId, headers, true) + } + + const fullCallbackUrl = `${endpoint}/bulkQuotes/${bulkQuoteId}` + // we need to strip off the 'accept' header + // for all PUT requests as per the API Specification Document + // https://github.com/mojaloop/mojaloop-specification/blob/master/API%20Definition%20v1.0.pdf + const newHeaders = generateRequestHeaders(headers, true) + + this.writeLog(`Forwarding bulk quote response to endpoint: ${fullCallbackUrl}`) + this.writeLog(`Forwarding bulk quote response headers: ${JSON.stringify(newHeaders)}`) + this.writeLog(`Forwarding bulk quote response body: ${JSON.stringify(originalBulkQuoteResponse)}`) + + let opts = { + method: ENUM.Http.RestMethods.PUT, + url: fullCallbackUrl, + data: JSON.stringify(originalBulkQuoteResponse), + headers: newHeaders + } + + if (span) { + opts = span.injectContextToHttpRequest(opts) + span.audit(opts, EventSdk.AuditEventAction.egress) + } + + await httpRequest(opts, fspiopSource) + } catch (err) { + // any-error + this.writeLog(`Error forwarding bulk quote response to endpoint ${endpoint}: ${getStackOrInspect(err)}`) + throw ErrorHandler.ReformatFSPIOPError(err) + } + } + + /** + * Attempts to handle a bulk quote GET request by forwarding it to the destination DFSP + * + * @returns {undefined} + */ + async handleBulkQuoteGet (headers, bulkQuoteId, span) { + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const childSpan = span.getChild('qs_quote_forwardBulkQuoteGet') + try { + await childSpan.audit({ headers, params: { bulkQuoteId } }, EventSdk.AuditEventAction.start) + await this.forwardBulkQuoteGet(headers, bulkQuoteId, childSpan) + } catch (err) { + // any-error + // as we are on our own in this context, dont just rethrow the error, instead... + // get the model to handle it + this.writeLog(`Error forwarding bulk quote get: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) + await this.handleException(fspiopSource, bulkQuoteId, err, headers, childSpan) + } finally { + if (childSpan && !childSpan.isFinished) { + await childSpan.finish() + } + } + } + + /** + * Attempts to forward a bulk quote GET request + * + * @returns {undefined} + */ + async forwardBulkQuoteGet (headers, bulkQuoteId, span) { + let endpoint + try { + // lookup payee dfsp callback endpoint + // todo: for MVP we assume initiator is always payer dfsp! this may not always be the case if a xfer is requested by payee + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_BULK_QUOTES') + + this.writeLog(`Resolved ${fspiopDest} FSPIOP_CALLBACK_URL_BULK_QUOTES endpoint for bulk quote GET ${bulkQuoteId} to: ${util.inspect(endpoint)}`) + + if (!endpoint) { + // we didnt get an endpoint for the payee dfsp! + // make an error callback to the initiator + // internal-error + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, `No FSPIOP_CALLBACK_URL_BULK_QUOTES found for bulk quote GET ${bulkQuoteId}`, null, fspiopSource) + } + + const fullCallbackUrl = `${endpoint}/bulkQuotes/${bulkQuoteId}` + const newHeaders = generateRequestHeaders(headers) + + this.writeLog(`Forwarding quote get request to endpoint: ${fullCallbackUrl}`) + + let opts = { + method: ENUM.Http.RestMethods.GET, + url: fullCallbackUrl, + headers: newHeaders + } + + if (span) { + opts = span.injectContextToHttpRequest(opts) + span.audit(opts, EventSdk.AuditEventAction.egress) + } + + await httpRequest(opts, fspiopSource) + } catch (err) { + // any-error + this.writeLog(`Error forwarding quote get request: ${getStackOrInspect(err)}`) + throw ErrorHandler.ReformatFSPIOPError(err) + } + } + + /** + * Handles error reports from clients e.g. POST bulkQuotes/{id}/error + * + * @returns {undefined} + */ + async handleBulkQuoteError (headers, bulkQuoteId, error, span) { + let newError + const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + const childSpan = span.getChild('qs_quote_forwardBulkQuoteError') + try { + // create a new object to represent the error + const fspiopError = ErrorHandler.CreateFSPIOPErrorFromErrorInformation(error) + await childSpan.audit({ headers, params: { bulkQuoteId } }, EventSdk.AuditEventAction.start) + // Needed to add await here to prevent 'span already finished' bug + await this.sendErrorCallback(headers[ENUM.Http.Headers.FSPIOP.DESTINATION], fspiopError, bulkQuoteId, headers, childSpan, false) + return newError + } catch (err) { + // internal-error + this.writeLog(`Error in handleBulkQuoteError: ${getStackOrInspect(err)}`) + await this.handleException(fspiopSource, bulkQuoteId, err, headers, childSpan) + } finally { + if (childSpan && !childSpan.isFinished) { + await childSpan.finish() + } + } + } + + /** + * Attempts to handle an exception in a sensible manner by forwarding it on to the + * source of the request that caused the error. + */ + async handleException (fspiopSource, bulkQuoteId, error, headers, span) { + // is this exception already wrapped as an API spec compatible type? + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + + const childSpan = span.getChild('qs_bulkQuote_sendErrorCallback') + try { + await childSpan.audit({ headers, params: { bulkQuoteId } }, EventSdk.AuditEventAction.start) + return await this.sendErrorCallback(fspiopSource, fspiopError, bulkQuoteId, headers, childSpan, true) + } catch (err) { + // any-error + // not much we can do other than log the error + this.writeLog(`Error occurred while handling error. Check service logs as this error may not have been propagated successfully to any other party: ${getStackOrInspect(err)}`) + } finally { + if (!childSpan.isFinished) { + await childSpan.finish() + } + } + } + + /** + * Makes an error callback. Callback is sent to the FSPIOP_CALLBACK_URL_QUOTES endpoint of the replyTo participant in the + * supplied fspiopErr object. This should be the participantId for the error callback recipient e.g. value from the + * FSPIOP-Source header of the original request that caused the error. + * + * @returns {promise} + */ + async sendErrorCallback (fspiopSource, fspiopError, bulkQuoteId, headers, span, modifyHeaders = true) { + const envConfig = new Config() + const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + try { + // look up the callback base url + const endpoint = await this.db.getParticipantEndpoint(fspiopSource, ENUM.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_BULK_QUOTES) + + this.writeLog(`Resolved participant '${fspiopSource}' '${ENUM.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_BULK_QUOTES}' to: '${endpoint}'`) + + if (!endpoint) { + // oops, we cant make an error callback if we dont have an endpoint to call! + // internal-error + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND, `No FSPIOP_CALLBACK_URL_BULK_QUOTES found for ${fspiopSource} unable to make error callback`, null, fspiopSource) + } + + const fspiopUri = `/bulkQuotes/${bulkQuoteId}/error` + const fullCallbackUrl = `${endpoint}${fspiopUri}` + + // log the original error + this.writeLog(`Making error callback to participant '${fspiopSource}' for bulkQuoteId '${bulkQuoteId}' to ${fullCallbackUrl} for error: ${util.inspect(fspiopError.toFullErrorObject())}`) + + // make an error callback + let fromSwitchHeaders + let formattedHeaders + + // modify/set the headers only in case it is explicitly requested to do so + // as this part needs to cover two different cases: + // 1. (do not modify them) when the Switch needs to relay an error, e.g. from a DFSP to another + // 2. (modify/set them) when the Switch needs send errors that are originating in the Switch, e.g. to send an error back to the caller + if (modifyHeaders === true) { + // Should not forward 'fspiop-signature' header for switch generated messages + delete headers['fspiop-signature'] + fromSwitchHeaders = Object.assign({}, headers, { + 'fspiop-destination': fspiopSource, + 'fspiop-source': ENUM.Http.Headers.FSPIOP.SWITCH.value, + 'fspiop-http-method': ENUM.Http.RestMethods.PUT, + 'fspiop-uri': fspiopUri + }) + } else { + fromSwitchHeaders = Object.assign({}, headers) + } + + // JWS Signer expects headers in lowercase + if (envConfig.jws && envConfig.jws.jwsSign && fromSwitchHeaders['fspiop-source'] === envConfig.jws.fspiopSourceToSign) { + formattedHeaders = generateRequestHeadersForJWS(fromSwitchHeaders, true) + } else { + formattedHeaders = generateRequestHeaders(fromSwitchHeaders, true) + } + + let opts = { + method: ENUM.Http.RestMethods.PUT, + url: fullCallbackUrl, + data: JSON.stringify(fspiopError.toApiErrorObject(envConfig.errorHandling), LibUtil.getCircularReplacer()), + // use headers of the error object if they are there... + // otherwise use sensible defaults + headers: formattedHeaders + } + + if (span) { + opts = span.injectContextToHttpRequest(opts) + span.audit(opts, EventSdk.AuditEventAction.egress) + } + + let res + try { + // If JWS is enabled and the 'fspiop-source' matches the configured jws header value('switch') + // that means it's a switch generated message and we need to sign it + if (envConfig.jws && envConfig.jws.jwsSign && opts.headers['fspiop-source'] === envConfig.jws.fspiopSourceToSign) { + const logger = Logger + logger.log = logger.info + this.writeLog('Getting the JWS Signer to sign the switch generated message') + const jwsSigner = new JwsSigner({ + logger, + signingKey: envConfig.jws.jwsSigningKey + }) + opts.headers['fspiop-signature'] = jwsSigner.getSignature(opts) + } + + res = await axios.request(opts) + } catch (err) { + // external-error + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, `network error in sendErrorCallback: ${err.message}`, { + error: err, + url: fullCallbackUrl, + sourceFsp: fspiopSource, + destinationFsp: fspiopDest, + method: opts && opts.method, + request: JSON.stringify(opts, LibUtil.getCircularReplacer()) + }, fspiopSource) + } + this.writeLog(`Error callback got response ${res.status} ${res.statusText}`) + + if (res.status !== ENUM.Http.ReturnCodes.OK.CODE) { + // external-error + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, 'Got non-success response sending error callback', { + url: fullCallbackUrl, + sourceFsp: fspiopSource, + destinationFsp: fspiopDest, + method: opts && opts.method, + request: JSON.stringify(opts, LibUtil.getCircularReplacer()), + response: JSON.stringify(res, LibUtil.getCircularReplacer()) + }, fspiopSource) + } + } catch (err) { + // any-error + this.writeLog(`Error in sendErrorCallback: ${getStackOrInspect(err)}`) + const fspiopError = ErrorHandler.ReformatFSPIOPError(err) + const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) + if (span) { + await span.error(fspiopError, state) + await span.finish(fspiopError.message, state) + } + throw fspiopError + } + } + + /** + * Writes a formatted message to the console + * + * @returns {undefined} + */ + // eslint-disable-next-line no-unused-vars + writeLog (message) { + Logger.info(`${new Date().toISOString()}, (${this.requestId}) [bulkQuotesModel]: ${message}`) + } +} + +module.exports = BulkQuotesModel diff --git a/src/model/quotes.js b/src/model/quotes.js index a9afd58f..b60e6fe4 100644 --- a/src/model/quotes.js +++ b/src/model/quotes.js @@ -30,69 +30,31 @@ - Henk Kodde - Matt Kingston - Vassilis Barzokas + - Shashikant Hirugade -------------- ******/ const axios = require('axios') -const Config = require('../lib/config') -const crypto = require('crypto') +const util = require('util') + const ENUM = require('@mojaloop/central-services-shared').Enum const ErrorHandler = require('@mojaloop/central-services-error-handling') const EventSdk = require('@mojaloop/event-sdk') const LibUtil = require('@mojaloop/central-services-shared').Util -const LOCAL_ENUM = require('../lib/enum') const Logger = require('@mojaloop/central-services-logger') const MLNumber = require('@mojaloop/ml-number') +const JwsSigner = require('@mojaloop/sdk-standard-components').Jws.signer + +const Config = require('../lib/config') +const { httpRequest } = require('../lib/http') +const { getStackOrInspect, generateRequestHeadersForJWS, generateRequestHeaders, calculateRequestHash, fetchParticipantInfo } = require('../lib/util') +const LOCAL_ENUM = require('../lib/enum') +const rules = require('../../config/rules.json') const RulesEngine = require('./rules.js') -const rules = require('../../config/rules.example.json') -const util = require('util') delete axios.defaults.headers.common.Accept delete axios.defaults.headers.common['Content-Type'] -// TODO: where httpRequest is called, there's a pretty common pattern of obtaining an endpoint from -// the database, specialising a template string with that endpoint, then calling httpRequest. Is -// there common functionality in these places than can reasonably be factored out? -/** - * Encapsulates making an HTTP request and translating any error response into a domain-specific - * error type. - * - * @param {Object} opts - * @param {String} fspiopSource - * @returns {Promise} - */ -const httpRequest = async (opts, fspiopSource) => { - // Network errors lob an exception. Bear in mind 3xx 4xx and 5xx are not network errors so we - // need to wrap the request below in a `try catch` to handle network errors - let res - let body - - try { - res = await axios.request(opts) - body = await res.data - } catch (e) { - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, - 'Network error', - `${e.stack || util.inspect(e)}. Opts: ${util.inspect(opts)}`, - fspiopSource) - } - - // handle non network related errors below - if (res.status < 200 || res.status >= 300) { - const errObj = util.inspect({ - opts, - status: res.status, - statusText: res.statusText, - body - }) - - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR, - 'Non-success response in HTTP request', - `${errObj}`, - fspiopSource) - } -} - /** * Encapsulates operations on the quotes domain model * @@ -105,22 +67,11 @@ class QuotesModel { this.requestId = config.requestId } - async executeRules (headers, quoteRequest) { + async executeRules (headers, quoteRequest, payer, payee) { if (rules.length === 0) { return [] } - // Collect facts to supply to the rule engine - // Get quote participants from central ledger admin - const { switchEndpoint } = new Config() - const url = `${switchEndpoint}/participants` - const [payer, payee] = await Promise.all([ - axios.request({ url: `${url}/${headers['fspiop-source']}` }), - axios.request({ url: `${url}/${headers['fspiop-destination']}` }) - ]) - - this.writeLog(`Got rules engine facts payer ${payer} and payee ${payee}`) - const facts = { payer, payee, @@ -130,7 +81,7 @@ class QuotesModel { const { events } = await RulesEngine.run(rules, facts) - this.writeLog(`Rules engine returned events ${events}`) + this.writeLog(`Rules engine returned events ${JSON.stringify(events)}`) return events } @@ -144,6 +95,14 @@ class QuotesModel { const { INVALID_QUOTE_REQUEST, INTERCEPT_QUOTE } = RulesEngine.events + const unhandledEvents = events.filter(ev => !(ev.type in RulesEngine.events)) + + if (unhandledEvents.length > 0) { + // The rules configuration contains events not handled in the code + // TODO: validate supplied rules at startup and fail if any invalid rules are discovered. + throw new Error('Unhandled event returned by rules engine') + } + const invalidQuoteRequestEvents = events.filter(ev => ev.type === INVALID_QUOTE_REQUEST) if (invalidQuoteRequestEvents.length > 0) { // Use the first event, ignore the others for now. This is ergonomically worse for someone @@ -152,7 +111,7 @@ class QuotesModel { const { FSPIOPError: code, message } = invalidQuoteRequestEvents[0].params // Will throw an internal server error if property doesn't exist throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes[code], - `Quote request ${quoteRequest.quoteId} failed: ${message}`, null, headers['fspiop-source']) + message, null, headers['fspiop-source']) } const interceptQuoteEvents = events.filter(ev => ev.type === INTERCEPT_QUOTE) @@ -162,7 +121,7 @@ class QuotesModel { } if (interceptQuoteEvents.length > 0) { // send the quote request to the recipient in the event - return { + const result = { terminate: false, quoteRequest, headers: { @@ -170,17 +129,23 @@ class QuotesModel { 'fspiop-destination': interceptQuoteEvents[0].params.rerouteToFsp } } + // if additionalHeaders are present then add the additional non-standard headers (e.g. used by forex) + // Note these headers are not part of the mojaloop specification + if (interceptQuoteEvents[0].params.additionalHeaders) { + result.headers = { ...result.headers, ...interceptQuoteEvents[0].params.additionalHeaders } + result.additionalHeaders = interceptQuoteEvents[0].params.additionalHeaders + } + return result } - - throw new Error('Unhandled event returned by rules engine') } /** - * Validates the quote request object - * - * @returns {promise} - promise will reject if request is not valid - */ - async validateQuoteRequest (fspiopSource, fspiopDestination, quoteRequest) { + * Validates the quote request object + * + * @returns {promise} - promise will reject if request is not valid + */ + async validateQuoteRequest (fspiopSource, fspiopDestination, quoteRequest, payer, payee) { + const envConfig = new Config() // note that the framework should validate the form of the request // here we can do some hard-coded rule validations to ensure requests // do not lead to unsupported scenarios or use-cases. @@ -195,53 +160,92 @@ class QuotesModel { // internal-error throw ErrorHandler.CreateInternalServerFSPIOPError('Missing quoteRequest', null, fspiopSource) } - await this.db.getParticipant(fspiopSource, LOCAL_ENUM.PAYER_DFSP) - await this.db.getParticipant(fspiopDestination, LOCAL_ENUM.PAYEE_DFSP) + + // Following is the validation to make sure valid fsp's are used in the payload for simple routing mode + if (envConfig.simpleRoutingMode) { + // Lets make sure the optional fspId exists in the payer's partyIdInfo before we validate it + if (quoteRequest.payer && quoteRequest.payer.partyIdInfo && quoteRequest.payer.partyIdInfo.fspId) { + await this.db.getParticipant(quoteRequest.payer.partyIdInfo.fspId, LOCAL_ENUM.PAYER_DFSP, quoteRequest.amount.currency, ENUM.Accounts.LedgerAccountType.POSITION) + } + // Lets make sure the optional fspId exists in the payee's partyIdInfo before we validate it + if (quoteRequest.payee && quoteRequest.payee.partyIdInfo && quoteRequest.payee.partyIdInfo.fspId) { + await this.db.getParticipant(quoteRequest.payee.partyIdInfo.fspId, LOCAL_ENUM.PAYEE_DFSP, quoteRequest.amount.currency, ENUM.Accounts.LedgerAccountType.POSITION) + } + } + + // check if the payer is active fsp, if not send error callback to payer + if (payer.isActive === 0) { + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PAYER_FSP_ID_NOT_FOUND, + `Payer FSP ID not found - Unsupported participant '${fspiopSource}'`, null, fspiopSource) + } + // check if the payee is active fsp, if not send error callback to payer + if (payee.isActive === 0) { + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, + `Destination FSP Error - '${fspiopDestination}' is inactive`, null, fspiopSource) + } + + const payerAccounts = Array.isArray(payer.accounts) ? payer.accounts : [] + const payeeAccounts = Array.isArray(payee.accounts) ? payee.accounts : [] + + const activePayerAccounts = payerAccounts.filter(account => account.isActive === 1 && account.ledgerAccountType === 'POSITION') + const activePayeeAccounts = payeeAccounts.filter(account => account.isActive === 1 && account.ledgerAccountType === 'POSITION') + + // check if the payer has atleast one active account, if not send error callback to payer + if (activePayerAccounts.length === 0) { + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PAYER_ERROR, + 'Payer does not have any active account', null, fspiopSource) + } + // check if the payee has atleast one active account, if not send error callback to payer + if (activePayeeAccounts.length === 0) { + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PAYEE_ERROR, + 'Payee does not have any active account', null, fspiopSource) + } } /** - * Validates the form of a quote update object - * - * @returns {promise} - promise will reject if request is not valid - */ + * Validates the form of a quote update object + * + * @returns {promise} - promise will reject if request is not valid + */ async validateQuoteUpdate () { // todo: actually do the validation (use joi as per mojaloop) return Promise.resolve(null) } /** - * Logic for creating and handling quote requests - * - * @returns {object} - returns object containing keys for created database entities - */ + * Logic for creating and handling quote requests + * + * @returns {object} - returns object containing keys for created database entities + */ async handleQuoteRequest (headers, quoteRequest, span) { const envConfig = new Config() - let txn = null + // accumulate enum ids + const refs = {} + let txn + let handledRuleEvents + let fspiopSource + const handleQuoteRequestSpan = span.getChild('qs_quote_handleQuoteRequest') try { - const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] const fspiopDestination = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] + const { payer, payee } = await fetchParticipantInfo(fspiopSource, fspiopDestination) + this.writeLog(`Got payer ${payer} and payee ${payee}`) + // validate - this will throw if the request is invalid + await this.validateQuoteRequest(fspiopSource, fspiopDestination, quoteRequest, payer, payee) + // Run the rules engine. If the user does not want to run the rules engine, they need only to // supply a rules file containing an empty array. - const events = await this.executeRules(headers, quoteRequest) + const events = await this.executeRules(headers, quoteRequest, payer, payee) - const handledRuleEvents = await this.handleRuleEvents(events, headers, quoteRequest) + handledRuleEvents = await this.handleRuleEvents(events, headers, quoteRequest) if (handledRuleEvents.terminate) { return } - // accumulate enum ids - const refs = {} - - // validate - this will throw if the request is invalid - await this.validateQuoteRequest(fspiopSource, fspiopDestination, quoteRequest) - if (!envConfig.simpleRoutingMode) { - // do everything in a db txn so we can rollback multiple operations if something goes wrong - txn = await this.db.newTransaction() - // check if this is a resend or an erroneous duplicate const dupe = await this.checkDuplicateQuoteRequest(quoteRequest) @@ -251,25 +255,31 @@ class QuotesModel { if (dupe.isDuplicateId && (!dupe.isResend)) { // same quoteId but a different request, this is an error! // internal-error - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST, `Quote ${quoteRequest.quoteId} is a duplicate but hashes dont match`, null, fspiopSource) + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST, + `Quote ${quoteRequest.quoteId} is a duplicate but hashes dont match`, null, fspiopSource) } if (dupe.isResend && dupe.isDuplicateId) { // this is a resend // See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. return this.handleQuoteRequestResend(handledRuleEvents.headers, - handledRuleEvents.quoteRequest, span) + handledRuleEvents.quoteRequest, handleQuoteRequestSpan, handledRuleEvents.additionalHeaders) } + // do everything in a db txn so we can rollback multiple operations if something goes wrong + txn = await this.db.newTransaction() + // todo: validation // if we get here we need to create a duplicate check row - const hash = this.calculateRequestHash(quoteRequest) + const hash = calculateRequestHash(quoteRequest) await this.db.createQuoteDuplicateCheck(txn, quoteRequest.quoteId, hash) // create a txn reference + this.writeLog(`Creating transactionReference for quoteId: ${quoteRequest.quoteId} and transactionId: ${quoteRequest.transactionId}`) refs.transactionReferenceId = await this.db.createTransactionReference(txn, quoteRequest.quoteId, quoteRequest.transactionId) + this.writeLog(`transactionReference created transactionReferenceId: ${refs.transactionReferenceId}`) // get the initiator type refs.transactionInitiatorTypeId = await this.db.getInitiatorType(quoteRequest.transactionType.initiatorType) @@ -314,6 +324,13 @@ class QuotesModel { refs.payeeId = await this.db.createPayeeQuoteParty(txn, refs.quoteId, quoteRequest.payee, quoteRequest.amount.amount, quoteRequest.amount.currency) + // store any extension list items + if (quoteRequest.extensionList && + Array.isArray(quoteRequest.extensionList.extension)) { + refs.extensions = await this.db.createQuoteExtensions( + txn, quoteRequest.extensionList.extension, quoteRequest.quoteId, quoteRequest.transactionId) + } + // did we get a geoCode for the initiator? if (quoteRequest.geoCode) { // eslint-disable-next-line require-atomic-updates @@ -326,65 +343,68 @@ class QuotesModel { await txn.commit() this.writeLog(`create quote transaction committed to db: ${util.inspect(refs)}`) - - // if we got here, all entities have been created in db correctly to record the quote request } // if we got here rules passed, so we can forward the quote on to the recipient dfsp - const childSpan = span.getChild('qs_quote_forwardQuoteRequest') - try { - if (envConfig.simpleRoutingMode) { - await childSpan.audit({ headers, payload: quoteRequest }, EventSdk.AuditEventAction.start) - await this.forwardQuoteRequest(handledRuleEvents.headers, quoteRequest.quoteId, handledRuleEvents.quoteRequest, childSpan) - } else { - await childSpan.audit({ headers, payload: refs }, EventSdk.AuditEventAction.start) - await this.forwardQuoteRequest(handledRuleEvents.headers, refs.quoteId, handledRuleEvents.quoteRequest, childSpan) - } - } catch (err) { - // any-error - // as we are on our own in this context, dont just rethrow the error, instead... - // get the model to handle it - this.writeLog(`Error forwarding quote request: ${err.stack || util.inspect(err)}. Attempting to send error callback to ${fspiopSource}`) - if (envConfig.simpleRoutingMode) { - await this.handleException(fspiopSource, quoteRequest.quoteId, err, headers, childSpan) - } else { - await this.handleException(fspiopSource, refs.quoteId, err, headers, childSpan) - } - } finally { - if (!childSpan.isFinished) { - await childSpan.finish() - } - } - - // all ok, return refs - return refs } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteRequest for quoteId ${quoteRequest.quoteId}: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in handleQuoteRequest for quoteId ${quoteRequest.quoteId}: ${getStackOrInspect(err)}`) if (txn) { txn.rollback(err) } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) - if (span) { - await span.error(fspiopError, state) - await span.finish(fspiopError.message, state) + await this.handleException(fspiopSource, quoteRequest.quoteId, fspiopError, headers, handleQuoteRequestSpan) + if (handleQuoteRequestSpan) { + await handleQuoteRequestSpan.error(fspiopError, state) + await handleQuoteRequestSpan.finish(fspiopError.message, state) } throw fspiopError } + let forwardQuoteRequestSpan + try { + forwardQuoteRequestSpan = handleQuoteRequestSpan.getChild('qs_quote_forwardQuoteRequest') + if (envConfig.simpleRoutingMode) { + await forwardQuoteRequestSpan.audit({ headers, payload: quoteRequest }, EventSdk.AuditEventAction.start) + await this.forwardQuoteRequest(handledRuleEvents.headers, quoteRequest.quoteId, handledRuleEvents.quoteRequest, forwardQuoteRequestSpan) + } else { + await forwardQuoteRequestSpan.audit({ headers, payload: refs }, EventSdk.AuditEventAction.start) + await this.forwardQuoteRequest(handledRuleEvents.headers, refs.quoteId, handledRuleEvents.quoteRequest, forwardQuoteRequestSpan, handledRuleEvents.additionalHeaders) + } + } catch (err) { + // any-error + // as we are on our own in this context, dont just rethrow the error, instead... + // get the model to handle it + this.writeLog(`Error forwarding quote request: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) + if (envConfig.simpleRoutingMode) { + await this.handleException(fspiopSource, quoteRequest.quoteId, err, headers, forwardQuoteRequestSpan) + } else { + await this.handleException(fspiopSource, refs.quoteId, err, headers, forwardQuoteRequestSpan) + } + } finally { + if (!forwardQuoteRequestSpan.isFinished) { + await forwardQuoteRequestSpan.finish() + } + if (!handleQuoteRequestSpan.isFinished) { + await handleQuoteRequestSpan.finish() + } + } + + // all ok, return refs + return refs } /** - * Forwards a quote request to a payee DFSP for processing - * - * @returns {undefined} - */ - async forwardQuoteRequest (headers, quoteId, originalQuoteRequest, span) { + * Forwards a quote request to a payee DFSP for processing + * + * @returns {undefined} + */ + async forwardQuoteRequest (headers, quoteId, originalQuoteRequest, span, additionalHeaders) { let endpoint const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] - const envConfig = new Config() + // const envConfig = new Config() try { if (!originalQuoteRequest) { @@ -395,13 +415,9 @@ class QuotesModel { // lookup payee dfsp callback endpoint // TODO: for MVP we assume initiator is always payer dfsp! this may not always be the // case if a xfer is requested by payee - if (envConfig.simpleRoutingMode) { - endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_QUOTES') - } else { - endpoint = await this.db.getQuotePartyEndpoint(quoteId, 'FSPIOP_CALLBACK_URL_QUOTES', 'PAYEE') - } + endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_QUOTES') - this.writeLog(`Resolved PAYEE party FSPIOP_CALLBACK_URL_QUOTES endpoint for quote ${quoteId} to: ${util.inspect(endpoint)}`) + this.writeLog(`Resolved PAYEE party FSPIOP_CALLBACK_URL_QUOTES endpoint for quote ${quoteId} to: ${endpoint}, destination: ${fspiopDest}`) if (!endpoint) { // internal-error @@ -411,7 +427,7 @@ class QuotesModel { } const fullCallbackUrl = `${endpoint}/quotes` - const newHeaders = this.generateRequestHeaders(headers) + const newHeaders = generateRequestHeaders(headers, false, additionalHeaders) this.writeLog(`Forwarding quote request to endpoint: ${fullCallbackUrl}`) this.writeLog(`Forwarding quote request headers: ${JSON.stringify(newHeaders)}`) @@ -433,16 +449,16 @@ class QuotesModel { await httpRequest(opts, fspiopSource) } catch (err) { // any-error - this.writeLog(`Error forwarding quote request to endpoint ${endpoint}: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error forwarding quote request to endpoint ${endpoint}: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Deals with resends of quote requests (POST) under the API spec: - * See section 3.2.5.1, 9.4 and 9.5 in "API Definition v1.0.docx" API specification document. - */ - async handleQuoteRequestResend (headers, quoteRequest, span) { + * Deals with resends of quote requests (POST) under the API spec: + * See section 3.2.5.1, 9.4 and 9.5 in "API Definition v1.0.docx" API specification document. + */ + async handleQuoteRequestResend (headers, quoteRequest, span, additionalHeaders) { try { const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] this.writeLog(`Handling resend of quoteRequest: ${util.inspect(quoteRequest)} from ${fspiopSource} to ${headers[ENUM.Http.Headers.FSPIOP.DESTINATION]}`) @@ -455,12 +471,12 @@ class QuotesModel { const childSpan = span.getChild('qs_quote_forwardQuoteRequestResend') try { await childSpan.audit({ headers, payload: quoteRequest }, EventSdk.AuditEventAction.start) - await this.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest, childSpan) + await this.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest, childSpan, additionalHeaders) } catch (err) { // any-error // as we are on our own in this context, dont just rethrow the error, instead... // get the model to handle it - this.writeLog(`Error forwarding quote request: ${err.stack || util.inspect(err)}. Attempting to send error callback to ${fspiopSource}`) + this.writeLog(`Error forwarding quote request: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) const fspiopError = ErrorHandler.ReformatFSPIOPError(err) await this.handleException(fspiopSource, quoteRequest.quoteId, fspiopError, headers, childSpan) } finally { @@ -470,20 +486,21 @@ class QuotesModel { } } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteRequestResend: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in handleQuoteRequestResend: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Logic for handling quote update requests e.g. PUT /quotes/{id} requests - * - * @returns {object} - object containing updated entities - */ + * Logic for handling quote update requests e.g. PUT /quotes/{id} requests + * + * @returns {object} - object containing updated entities + */ async handleQuoteUpdate (headers, quoteId, quoteUpdateRequest, span) { let txn = null const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] const envConfig = new Config() + const handleQuoteUpdateSpan = span.getChild('qs_quote_handleQuoteUpdate') try { // ensure no 'accept' header is present in the request headers. if ('accept' in headers) { @@ -495,9 +512,6 @@ class QuotesModel { // accumulate enum ids const refs = {} if (!envConfig.simpleRoutingMode) { - // do everything in a transaction so we can rollback multiple operations if something goes wrong - txn = await this.db.newTransaction() - // check if this is a resend or an erroneous duplicate const dupe = await this.checkDuplicateQuoteResponse(quoteId, quoteUpdateRequest) this.writeLog(`Check duplicate for quoteId ${quoteId} update returned: ${util.inspect(dupe)}`) @@ -512,9 +526,12 @@ class QuotesModel { if (dupe.isResend && dupe.isDuplicateId) { // this is a resend // See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. - return this.handleQuoteUpdateResend(headers, quoteId, quoteUpdateRequest, span) + return this.handleQuoteUpdateResend(headers, quoteId, quoteUpdateRequest, handleQuoteUpdateSpan) } + // do everything in a transaction so we can rollback multiple operations if something goes wrong + txn = await this.db.newTransaction() + // todo: validation // create the quote response row in the db @@ -531,7 +548,7 @@ class QuotesModel { refs.quoteResponseId = newQuoteResponse.quoteResponseId // if we get here we need to create a duplicate check row - const hash = this.calculateRequestHash(quoteUpdateRequest) + const hash = calculateRequestHash(quoteUpdateRequest) await this.db.createQuoteUpdateDuplicateCheck(txn, quoteId, refs.quoteResponseId, hash) // create ilp packet in the db @@ -554,6 +571,13 @@ class QuotesModel { }) } + // store any extension list items + if (quoteUpdateRequest.extensionList && + Array.isArray(quoteUpdateRequest.extensionList.extension)) { + refs.extensions = await this.db.createQuoteExtensions( + txn, quoteUpdateRequest.extensionList.extension, quoteId, null, refs.quoteResponseId) + } + // todo: create any additional quoteParties e.g. for fees, comission etc... await txn.commit() @@ -572,7 +596,7 @@ class QuotesModel { // } } // if we got here rules passed, so we can forward the quote on to the recipient dfsp - const childSpan = span.getChild('qs_quote_forwardQuoteUpdate') + const childSpan = handleQuoteUpdateSpan.getChild('qs_quote_forwardQuoteUpdate') try { await childSpan.audit({ headers, params: { quoteId }, payload: quoteUpdateRequest }, EventSdk.AuditEventAction.start) await this.forwardQuoteUpdate(headers, quoteId, quoteUpdateRequest, childSpan) @@ -581,40 +605,44 @@ class QuotesModel { // as we are on our own in this context, dont just rethrow the error, instead... // get the model to handle it const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] - this.writeLog(`Error forwarding quote update: ${err.stack || util.inspect(err)}. Attempting to send error callback to ${fspiopSource}`) + this.writeLog(`Error forwarding quote update: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) await this.handleException(fspiopSource, quoteId, err, headers, childSpan) } finally { if (!childSpan.isFinished) { await childSpan.finish() } + if (!handleQuoteUpdateSpan.isFinished) { + await handleQuoteUpdateSpan.finish() + } } // all ok, return refs return refs } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteUpdate: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in handleQuoteUpdate: ${getStackOrInspect(err)}`) if (txn) { txn.rollback(err) } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) - if (span) { - await span.error(fspiopError, state) - await span.finish(fspiopError.message, state) + await this.handleException(fspiopSource, quoteId, err, headers, handleQuoteUpdateSpan) + if (handleQuoteUpdateSpan) { + await handleQuoteUpdateSpan.error(fspiopError, state) + await handleQuoteUpdateSpan.finish(fspiopError.message, state) } throw fspiopError } } /** - * Forwards a quote response to a payer DFSP for processing - * - * @returns {undefined} - */ + * Forwards a quote response to a payer DFSP for processing + * + * @returns {undefined} + */ async forwardQuoteUpdate (headers, quoteId, originalQuoteResponse, span) { let endpoint = null - const envConfig = new Config() + // const envConfig = new Config() const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] @@ -626,12 +654,7 @@ class QuotesModel { } // lookup payer dfsp callback endpoint - if (envConfig.simpleRoutingMode) { - endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_QUOTES') - } else { - // todo: for MVP we assume initiator is always payer dfsp! this may not always be the case if a xfer is requested by payee - endpoint = await this.db.getQuotePartyEndpoint(quoteId, 'FSPIOP_CALLBACK_URL_QUOTES', 'PAYER') - } + endpoint = await this.db.getParticipantEndpoint(fspiopDest, 'FSPIOP_CALLBACK_URL_QUOTES') this.writeLog(`Resolved PAYER party FSPIOP_CALLBACK_URL_QUOTES endpoint for quote ${quoteId} to: ${util.inspect(endpoint)}`) @@ -639,14 +662,14 @@ class QuotesModel { // we didnt get an endpoint for the payee dfsp! // make an error callback to the initiator const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, `No FSPIOP_CALLBACK_URL_QUOTES found for quote ${quoteId} PAYER party`, null, fspiopSource) - return this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers) + return this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers, true) } const fullCallbackUrl = `${endpoint}/quotes/${quoteId}` // we need to strip off the 'accept' header // for all PUT requests as per the API Specification Document // https://github.com/mojaloop/mojaloop-specification/blob/master/API%20Definition%20v1.0.pdf - const newHeaders = this.generateRequestHeaders(headers, true) + const newHeaders = generateRequestHeaders(headers, true) this.writeLog(`Forwarding quote response to endpoint: ${fullCallbackUrl}`) this.writeLog(`Forwarding quote response headers: ${JSON.stringify(newHeaders)}`) @@ -667,15 +690,15 @@ class QuotesModel { await httpRequest(opts, fspiopSource) } catch (err) { // any-error - this.writeLog(`Error forwarding quote response to endpoint ${endpoint}: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error forwarding quote response to endpoint ${endpoint}: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Deals with resends of quote responses (PUT) under the API spec: - * See section 3.2.5.1, 9.4 and 9.5 in "API Definition v1.0.docx" API specification document. - */ + * Deals with resends of quote responses (PUT) under the API spec: + * See section 3.2.5.1, 9.4 and 9.5 in "API Definition v1.0.docx" API specification document. + */ async handleQuoteUpdateResend (headers, quoteId, quoteUpdate, span) { try { const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] @@ -695,7 +718,7 @@ class QuotesModel { // any-error // as we are on our own in this context, dont just rethrow the error, instead... // get the model to handle it - this.writeLog(`Error forwarding quote response: ${err.stack || util.inspect(err)}. Attempting to send error callback to ${fspiopSource}`) + this.writeLog(`Error forwarding quote response: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) await this.handleException(fspiopSource, quoteId, err, headers, childSpan) } finally { if (!childSpan.isFinished) { @@ -704,20 +727,21 @@ class QuotesModel { } } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteUpdateResend: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in handleQuoteUpdateResend: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Handles error reports from clients e.g. POST quotes/{id}/error - * - * @returns {undefined} - */ + * Handles error reports from clients e.g. POST quotes/{id}/error + * + * @returns {undefined} + */ async handleQuoteError (headers, quoteId, error, span) { let txn = null const envConfig = new Config() let newError + const childSpan = span.getChild('qs_quote_handleQuoteError') try { if (!envConfig.simpleRoutingMode) { // do everything in a transaction so we can rollback multiple operations if something goes wrong @@ -736,32 +760,36 @@ class QuotesModel { // create a new object to represent the error const fspiopError = ErrorHandler.CreateFSPIOPErrorFromErrorInformation(error) - this.sendErrorCallback(headers[ENUM.Http.Headers.FSPIOP.SOURCE], fspiopError, quoteId, headers, span) + // Needed to add await here to prevent 'childSpan already finished' bug + await this.sendErrorCallback(headers[ENUM.Http.Headers.FSPIOP.DESTINATION], fspiopError, quoteId, headers, childSpan, false) return newError } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteError: ${err.stack || util.inspect(err)}`) - txn.rollback(err) + this.writeLog(`Error in handleQuoteError: ${getStackOrInspect(err)}`) + if (txn) { + txn.rollback(err) + } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) - if (span) { - await span.error(fspiopError, state) - await span.finish(fspiopError.message, state) + if (childSpan) { + await childSpan.error(fspiopError, state) + await childSpan.finish(fspiopError.message, state) } throw fspiopError } } /** - * Attempts to handle a quote GET request by forwarding it to the destination DFSP - * - * @returns {undefined} - */ + * Attempts to handle a quote GET request by forwarding it to the destination DFSP + * + * @returns {undefined} + */ async handleQuoteGet (headers, quoteId, span) { const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] + let childSpan try { - const childSpan = span.getChild('qs_quote_forwardQuoteGet') + childSpan = span.getChild('qs_quote_forwardQuoteGet') try { await childSpan.audit({ headers, params: { quoteId } }, EventSdk.AuditEventAction.start) await this.forwardQuoteGet(headers, quoteId, childSpan) @@ -769,7 +797,7 @@ class QuotesModel { // any-error // as we are on our own in this context, dont just rethrow the error, instead... // get the model to handle it - this.writeLog(`Error forwarding quote get: ${err.stack || util.inspect(err)}. Attempting to send error callback to ${fspiopSource}`) + this.writeLog(`Error forwarding quote get: ${getStackOrInspect(err)}. Attempting to send error callback to ${fspiopSource}`) await this.handleException(fspiopSource, quoteId, err, headers, childSpan) } finally { if (!childSpan.isFinished) { @@ -778,27 +806,21 @@ class QuotesModel { } } catch (err) { // internal-error - this.writeLog(`Error in handleQuoteGet: ${err.stack || util.inspect(err)}`) - const fspiopError = ErrorHandler.ReformatFSPIOPError(err) - const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) - if (span) { - await span.error(fspiopError, state) - await span.finish(fspiopError.message, state) - } - throw fspiopError + this.writeLog(`Error in handleQuoteGet: ${getStackOrInspect(err)}`) + throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Attempts to forward a quote GET request - * - * @returns {undefined} - */ + * Attempts to forward a quote GET request + * + * @returns {undefined} + */ async forwardQuoteGet (headers, quoteId, span) { let endpoint try { - // we just need to forward this request on to the destinatin dfsp. they should response with a + // we just need to forward this request on to the destination dfsp. they should response with a // quote update resend (PUT) // lookup payee dfsp callback endpoint @@ -817,7 +839,7 @@ class QuotesModel { } const fullCallbackUrl = `${endpoint}/quotes/${quoteId}` - const newHeaders = this.generateRequestHeaders(headers) + const newHeaders = generateRequestHeaders(headers) this.writeLog(`Forwarding quote get request to endpoint: ${fullCallbackUrl}`) @@ -835,15 +857,15 @@ class QuotesModel { await httpRequest(opts, fspiopSource) } catch (err) { // any-error - this.writeLog(`Error forwarding quote get request: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error forwarding quote get request: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Attempts to handle an exception in a sensible manner by forwarding it on to the - * source of the request that caused the error. - */ + * Attempts to handle an exception in a sensible manner by forwarding it on to the + * source of the request that caused the error. + */ async handleException (fspiopSource, quoteId, error, headers, span) { // is this exception already wrapped as an API spec compatible type? const fspiopError = ErrorHandler.ReformatFSPIOPError(error) @@ -851,11 +873,11 @@ class QuotesModel { const childSpan = span.getChild('qs_quote_sendErrorCallback') try { await childSpan.audit({ headers, params: { quoteId } }, EventSdk.AuditEventAction.start) - return await this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers, childSpan) + return await this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers, childSpan, true) } catch (err) { // any-error // not much we can do other than log the error - this.writeLog(`Error occured handling error. check service logs as this error may not have been propagated successfully to any other party: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error occurred while handling error. Check service logs as this error may not have been propagated successfully to any other party: ${getStackOrInspect(err)}`) } finally { if (!childSpan.isFinished) { await childSpan.finish() @@ -864,13 +886,13 @@ class QuotesModel { } /** - * Makes an error callback. Callback is sent to the FSPIOP_CALLBACK_URL_QUOTES endpoint of the replyTo participant in the - * supplied fspiopErr object. This should be the participantId for the error callback recipient e.g. value from the - * FSPIOP-Source header of the original request that caused the error. - * - * @returns {promise} - */ - async sendErrorCallback (fspiopSource, fspiopError, quoteId, headers, span) { + * Makes an error callback. Callback is sent to the FSPIOP_CALLBACK_URL_QUOTES endpoint of the replyTo participant in the + * supplied fspiopErr object. This should be the participantId for the error callback recipient e.g. value from the + * FSPIOP-Source header of the original request that caused the error. + * + * @returns {promise} + */ + async sendErrorCallback (fspiopSource, fspiopError, quoteId, headers, span, modifyHeaders = true) { const envConfig = new Config() const fspiopDest = headers[ENUM.Http.Headers.FSPIOP.DESTINATION] try { @@ -885,23 +907,47 @@ class QuotesModel { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND, `No FSPIOP_CALLBACK_URL_QUOTES found for ${fspiopSource} unable to make error callback`, null, fspiopSource) } - const fullCallbackUrl = `${endpoint}/quotes/${quoteId}/error` + const fspiopUri = `/quotes/${quoteId}/error` + const fullCallbackUrl = `${endpoint}${fspiopUri}` // log the original error this.writeLog(`Making error callback to participant '${fspiopSource}' for quoteId '${quoteId}' to ${fullCallbackUrl} for error: ${util.inspect(fspiopError.toFullErrorObject())}`) // make an error callback + let fromSwitchHeaders + let formattedHeaders + + // modify/set the headers only in case it is explicitly requested to do so + // as this part needs to cover two different cases: + // 1. (do not modify them) when the Switch needs to relay an error, e.g. from a DFSP to another + // 2. (modify/set them) when the Switch needs send errors that are originating in the Switch, e.g. to send an error back to the caller + if (modifyHeaders === true) { + // Should not forward 'fspiop-signature' header for switch generated messages + delete headers['fspiop-signature'] + fromSwitchHeaders = Object.assign({}, headers, { + 'fspiop-destination': fspiopSource, + 'fspiop-source': ENUM.Http.Headers.FSPIOP.SWITCH.value, + 'fspiop-http-method': ENUM.Http.RestMethods.PUT, + 'fspiop-uri': fspiopUri + }) + } else { + fromSwitchHeaders = Object.assign({}, headers) + } + + // JWS Signer expects headers in lowercase + if (envConfig.jws && envConfig.jws.jwsSign && fromSwitchHeaders['fspiop-source'] === envConfig.jws.fspiopSourceToSign) { + formattedHeaders = generateRequestHeadersForJWS(fromSwitchHeaders, true) + } else { + formattedHeaders = generateRequestHeaders(fromSwitchHeaders, true) + } + let opts = { method: ENUM.Http.RestMethods.PUT, url: fullCallbackUrl, data: JSON.stringify(fspiopError.toApiErrorObject(envConfig.errorHandling), LibUtil.getCircularReplacer()), // use headers of the error object if they are there... // otherwise use sensible defaults - headers: this.generateRequestHeaders(headers || { - 'fspiop-destination': fspiopSource, - 'fspiop-source': ENUM.Http.Headers.FSPIOP.SWITCH.value, - 'fspiop-http-method': ENUM.Http.RestMethods.PUT - }, true) + headers: formattedHeaders } if (span) { @@ -911,6 +957,19 @@ class QuotesModel { let res try { + // If JWS is enabled and the 'fspiop-source' matches the configured jws header value('switch') + // that means it's a switch generated message and we need to sign it + if (envConfig.jws && envConfig.jws.jwsSign && opts.headers['fspiop-source'] === envConfig.jws.fspiopSourceToSign) { + const logger = Logger + logger.log = logger.info + this.writeLog('Getting the JWS Signer to sign the switch generated message') + const jwsSigner = new JwsSigner({ + logger, + signingKey: envConfig.jws.jwsSigningKey + }) + opts.headers['fspiop-signature'] = jwsSigner.getSignature(opts) + } + res = await axios.request(opts) } catch (err) { // external-error @@ -938,7 +997,7 @@ class QuotesModel { } } catch (err) { // any-error - this.writeLog(`Error in sendErrorCallback: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in sendErrorCallback: ${getStackOrInspect(err)}`) const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) if (span) { @@ -950,16 +1009,16 @@ class QuotesModel { } /** - * Tests to see if this quote request is a RESEND of a previous request or an inadvertant duplicate quoteId. - * - * See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. - * - * @returns {promise} - resolves to an object thus: { isResend: {boolean}, isDuplicateId: {boolean} } - */ + * Tests to see if this quote request is a RESEND of a previous request or an inadvertant duplicate quoteId. + * + * See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. + * + * @returns {promise} - resolves to an object thus: { isResend: {boolean}, isDuplicateId: {boolean} } + */ async checkDuplicateQuoteRequest (quoteRequest) { try { // calculate a SHA-256 of the request - const hash = this.calculateRequestHash(quoteRequest) + const hash = calculateRequestHash(quoteRequest) this.writeLog(`Calculated sha256 hash of quote request with id ${quoteRequest.quoteId} as: ${hash}`) const dupchk = await this.db.getQuoteDuplicateCheck(quoteRequest.quoteId) @@ -988,22 +1047,22 @@ class QuotesModel { } } catch (err) { // internal-error - this.writeLog(`Error in checkDuplicateQuoteRequest: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in checkDuplicateQuoteRequest: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Tests to see if this quote response is a RESEND of a previous response or an inadvertent duplicate quoteId. - * - * See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. - * - * @returns {promise} - resolves to an object thus: { isResend: {boolean}, isDuplicateId: {boolean} } - */ + * Tests to see if this quote response is a RESEND of a previous response or an inadvertent duplicate quoteId. + * + * See section 3.2.5.1 in "API Definition v1.0.docx" API specification document. + * + * @returns {promise} - resolves to an object thus: { isResend: {boolean}, isDuplicateId: {boolean} } + */ async checkDuplicateQuoteResponse (quoteId, quoteResponse) { try { // calculate a SHA-256 of the request - const hash = this.calculateRequestHash(quoteResponse) + const hash = calculateRequestHash(quoteResponse) this.writeLog(`Calculated sha256 hash of quote response with id ${quoteId} as: ${hash}`) const dupchk = await this.db.getQuoteResponseDuplicateCheck(quoteId) @@ -1032,78 +1091,16 @@ class QuotesModel { } } catch (err) { // internal-error - this.writeLog(`Error in checkDuplicateQuoteResponse: ${err.stack || util.inspect(err)}`) + this.writeLog(`Error in checkDuplicateQuoteResponse: ${getStackOrInspect(err)}`) throw ErrorHandler.ReformatFSPIOPError(err) } } /** - * Utility function to remove null and undefined keys from an object. - * This is useful for removing "nulls" that come back from database queries - * when projecting into API spec objects - * - * @returns {object} - */ - removeEmptyKeys (originalObject) { - const obj = { ...originalObject } - Object.keys(obj).forEach(key => { - if (obj[key] && typeof obj[key] === 'object') { - if (Object.keys(obj[key]).length < 1) { - // remove empty object - delete obj[key] - } else { - // recurse - obj[key] = this.removeEmptyKeys(obj[key]) - } - } else if (obj[key] == null) { - // null or undefined, remove it - delete obj[key] - } - }) - return obj - } - - /** - * Returns the SHA-256 hash of the supplied request object - * - * @returns {undefined} - */ - calculateRequestHash (request) { - // calculate a SHA-256 of the request - const requestStr = JSON.stringify(request) - return crypto.createHash('sha256').update(requestStr).digest('hex') - } - - /** - * Generates and returns an object containing API spec compliant HTTP request headers - * - * @returns {object} - */ - generateRequestHeaders (headers, noAccept) { - const ret = { - 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', - Date: headers.date, - 'FSPIOP-Source': headers['fspiop-source'], - 'FSPIOP-Destination': headers['fspiop-destination'], - 'FSPIOP-HTTP-Method': headers['fspiop-http-method'], - 'FSPIOP-Signature': headers['fspiop-signature'], - 'FSPIOP-URI': headers['fspiop-uri'], - 'User-Agent': null, // yuck! node-fetch INSISTS on sending a user-agent header!? infuriating! - Accept: null - } - - if (!noAccept) { - ret.Accept = 'application/vnd.interoperability.quotes+json;version=1' - } - - return this.removeEmptyKeys(ret) - } - - /** - * Writes a formatted message to the console - * - * @returns {undefined} - */ + * Writes a formatted message to the console + * + * @returns {undefined} + */ // eslint-disable-next-line no-unused-vars writeLog (message) { Logger.info(`${new Date().toISOString()}, (${this.requestId}) [quotesmodel]: ${message}`) diff --git a/src/model/rules.js b/src/model/rules.js index 0686ebe0..c8d0a430 100644 --- a/src/model/rules.js +++ b/src/model/rules.js @@ -37,10 +37,9 @@ */ const jre = require('json-rules-engine') -const jsonpath = require('jsonpath') const assert = require('assert').strict -module.exports.events = { +const events = { INTERCEPT_QUOTE: 'INTERCEPT_QUOTE', INVALID_QUOTE_REQUEST: 'INVALID_QUOTE_REQUEST' } @@ -66,97 +65,15 @@ const createEngine = () => { engine.addOperator('deepEqual', (factValue, ruleValue) => { return deepEqual(factValue, ruleValue) }) - - /** - * The json-rules-engine path only supports selectn paths. This is problematic, as selectn cannot - * traverse an array with filters, it can only use a static array index. For example, selectn - * cannot find the age of user with name 'Tutaia' in the following array, without knowing in - * advance that Tutaia will be the first element of the array: - * - * [ { name: 'Tutaia', age: 25 }, { name: 'Kim', age: 66 } ] - * - * In many (most) cases we cannot know the order and content of our data in advance. We therefore - * provide a more flexible, but still declarative jsonpath dynamic fact. Note that the examples - * provided below in this comment are reproduced in the tests. - * - * Note that the jsonPathFact requires the deepEqual operator to function correctly, as jsonpath - * returns an array of results. - * - * See https://www.npmjs.com/package/jsonpath for more information on jsonpath. - * - * The json-path fact exploits the fact params as its API by allowing the user to specify the fact - * they'd like to retrieve and a jsonpath within that fact. - * - * The following example looks at the payload fact, and checks whether the payer fspId, at jsonpath - * `$.payload.payer.partyIdInfo.fspId` is not `payerfsp`: - * - * { - * fact: 'json-path', - * params: { - * fact: 'payload', - * path: '$.payload.payer.partyIdInfo.fspId' - * }, - * operator: 'notDeepEqual', - * value: [ 'payerfsp' ] - * } - * - * Note that the value of .params.fact will be a top-level key in the jsonpath query, and therefore - * must correspond to the top-level key in .params.path. A general example: - * - * { - * fact: 'json-path', - * params: { - * fact: 'top-level-key', - * path: '$.top-level-key' - * }, - * ... - * } - * - * Supported top-level keys (facts) are: - * - payload - * - headers - * - payer - * - payee - * - * Another slightly more complex example, comparing the value of the fspiop-source header with the - * payer fspId in the payload: - * - * { - * fact: 'json-path', - * params: { - * fact: 'payload', - * path: '$.payload.payer.partyIdInfo.fspId' - * }, - * operator: 'deepEqual', - * value: { - * fact: 'json-path', - * params: { - * path: '$.headers[\'fspiop-source\']', - * fact: 'headers' - * } - * } - * } - * - * So far, no example rules have _required_ the use of jsonpath. The following rule filters the - * KYCPayerTier key in the extension list of the quote payload and verifies that it is '1': - * - * { - * fact: 'json-path', - * params: { - * fact: 'payload', - * path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' - * }, - * operator: 'deepEqual', - * value: [ '1' ] - * } - */ - const jsonPathFact = function (params, almanac) { - return almanac.factValue(params.fact) - .then((fact) => { - return jsonpath.query({ [params.fact]: fact }, params.path) - }) - } - engine.addFact('json-path', jsonPathFact) + engine.addOperator('isString', (factValue, ruleValue) => { + return ((typeof factValue === 'string') === ruleValue) + }) + engine.addOperator('isArray', (factValue, ruleValue) => { + return Array.isArray(factValue) === ruleValue + }) + engine.addOperator('isObject', (factValue, ruleValue) => { + return (typeof factValue === 'object' && !Array.isArray(factValue)) === ruleValue + }) return engine } @@ -166,9 +83,14 @@ const createEngine = () => { * * @returns {promise} - array of failure cases, may be empty */ -module.exports.run = (rules, runtimeFacts) => { +const run = (rules, runtimeFacts) => { const engine = createEngine() rules.map(r => new jre.Rule(r)).forEach(r => engine.addRule(r)) return engine.run(runtimeFacts) } + +module.exports = { + events, + run +} diff --git a/src/server.js b/src/server.js index b96af020..cde7579e 100644 --- a/src/server.js +++ b/src/server.js @@ -1,18 +1,60 @@ -'use strict' +// (C)2018 ModusBox Inc. +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. -const Hapi = require('@hapi/hapi') -const HapiOpenAPI = require('hapi-openapi') + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Henk Kodde + - Matt Kingston + - Vassilis Barzokas + -------------- + ******/ + +'use strict' const Path = require('path') +const Hapi = require('@hapi/hapi') +const Inert = require('@hapi/inert') +const Vision = require('@hapi/vision') const Good = require('@hapi/good') const Blipp = require('blipp') const ErrorHandler = require('@mojaloop/central-services-error-handling') const CentralServices = require('@mojaloop/central-services-shared') const HeaderValidation = require('@mojaloop/central-services-shared').Util.Hapi.FSPIOPHeaderValidation +const OpenapiBackend = require('@mojaloop/central-services-shared').Util.OpenapiBackend +const OpenapiBackendValidator = require('@mojaloop/central-services-shared').Util.Hapi.OpenapiBackendValidator const Logger = require('@mojaloop/central-services-logger') -const util = require('util') +const APIDocumentation = require('@mojaloop/central-services-shared').Util.Hapi.APIDocumentation +const { getStackOrInspect, failActionHandler } = require('../src/lib/util') const Config = require('./lib/config.js') -const Database = require('./data/cachedDatabase.js') +const Database = require('./data/cachedDatabase') +const Handlers = require('./handlers') +const Routes = require('./handlers/routes') + +const OpenAPISpecPath = Path.resolve(__dirname, './interface/QuotingService-swagger.yaml') /** * Initializes a database connection pool @@ -37,10 +79,7 @@ const initServer = async function (db, config) { port: config.listenPort, routes: { validate: { - failAction: async (request, h, err) => { - Logger.error(`validation failure: ${err.stack || util.inspect(err)}`) - throw err - } + failAction: failActionHandler } } }) @@ -48,37 +87,62 @@ const initServer = async function (db, config) { // put the database pool somewhere handlers can use it server.app.database = db - // add plugins to the server - await server.register([{ - plugin: HapiOpenAPI, + if (config.apiDocumentationEndpoints) { + await server.register({ + plugin: APIDocumentation, + options: { + documentPath: OpenAPISpecPath + } + }) + } + + const api = await OpenapiBackend.initialise(OpenAPISpecPath, Handlers) + await server.register(OpenapiBackendValidator) + await server.register({ + plugin: { + name: 'openapi', + version: '1.0.0', + multiple: true, + register: function (server, options) { + server.expose('openapi', options.openapi) + } + }, options: { - api: Path.resolve('./src/interface/swagger.json'), - handlers: Path.resolve('./src/handlers') + openapi: api } - }, { - plugin: Good, - options: { - ops: { - interval: 1000 - }, - reporters: { - console: [{ - module: 'good-squeeze', - name: 'Squeeze', - args: [{ log: '*', response: '*' }] - }, { - module: 'good-console', - args: [{ format: '' }] - }, 'stdout'] + }) + // add plugins to the server + await server.register([ + { + plugin: Good, + options: { + ops: { + interval: 1000 + }, + reporters: { + console: [{ + module: 'good-squeeze', + name: 'Squeeze', + args: [{ log: '*', response: '*' }] + }, { + module: 'good-console', + args: [{ format: '' }] + }, 'stdout'] + } } - } - }, - { - plugin: HeaderValidation - }, - Blipp, - ErrorHandler, - CentralServices.Util.Hapi.HapiEventPlugin]) + }, + { + plugin: HeaderValidation + }, + Inert, + Vision, + Blipp, + ErrorHandler, + CentralServices.Util.Hapi.HapiEventPlugin + ]) + + server.route(Routes.APIRoutes(api)) + // TODO: follow instructions https://github.com/anttiviljami/openapi-backend/blob/master/DOCS.md#postresponsehandler-handler // start the server await server.start() @@ -89,21 +153,31 @@ const initServer = async function (db, config) { // load config const config = new Config() -// initialise database connection pool and start the api server -initDb(config).then(db => { - return initServer(db, config) -}).then(server => { - process.on('SIGTERM', () => { - server.log(['info'], 'Received SIGTERM, closing server...') - server.stop({ timeout: 10000 }).then(err => { - Logger.warn(`server stopped. ${err ? (err.stack || util.inspect(err)) : ''}`) - process.exit((err) ? 1 : 0) +/** + * @function start + * @description Starts the web server + */ +async function start () { + // initialise database connection pool and start the api server + return initDb(config) + .then(db => initServer(db, config)) + .then(server => { + // Ignore coverage here as simulating `process.on('SIGTERM'...)` kills jest + /* istanbul ignore next */ + process.on('SIGTERM', () => { + server.log(['info'], 'Received SIGTERM, closing server...') + server.stop({ timeout: 10000 }) + .then(err => { + Logger.warn(`server stopped. ${err ? (getStackOrInspect(err)) : ''}`) + process.exit((err) ? 1 : 0) + }) + }) + server.log(['info'], `Server running on ${server.info.uri}`) + return server + // eslint-disable-next-line no-unused-vars + }).catch(err => { + Logger.error(`Error initializing server: ${getStackOrInspect(err)}`) }) - }) +} - server.plugins.openapi.setHost(server.info.host + ':' + server.info.port) - server.log(['info'], `Server running on ${server.info.uri}`) -// eslint-disable-next-line no-unused-vars -}).catch(err => { - Logger.error(`Error initializing server: ${err.stack || util.inspect(err)}`) -}) +module.exports = start diff --git a/test/unit/data/cachedDatabase.test.js b/test/unit/data/cachedDatabase.test.js new file mode 100644 index 00000000..6da37237 --- /dev/null +++ b/test/unit/data/cachedDatabase.test.js @@ -0,0 +1,191 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +const Config = require('../../../src/lib/config') +const CachedDatabase = require('../../../src/data/cachedDatabase') + +describe('cachedDatabase', () => { + describe('getCacheMethods', () => { + let cachedDb + + beforeEach(() => { + const config = new Config() + cachedDb = new CachedDatabase(config) + }) + + it('getInitiatorType', async () => { + // Arrange + cachedDb.cachePut('getInitiatorType', ['paramA'], 'testInitiatorTypeValue') + + // Act + const result = await cachedDb.getInitiatorType('paramA') + + // Assert + expect(result).toBe('testInitiatorTypeValue') + }) + + it('getInitiator', async () => { + // Arrange + cachedDb.cachePut('getInitiator', ['paramA'], 'getInitiatorValue') + + // Act + const result = await cachedDb.getInitiator('paramA') + + // Assert + expect(result).toBe('getInitiatorValue') + }) + + it('getScenario', async () => { + // Arrange + cachedDb.cachePut('getScenario', ['paramA'], 'getScenarioValue') + + // Act + const result = await cachedDb.getScenario('paramA') + + // Assert + expect(result).toBe('getScenarioValue') + }) + + it('getSubScenario', async () => { + // Arrange + cachedDb.cachePut('getSubScenario', ['paramA'], 'getSubScenarioValue') + + // Act + const result = await cachedDb.getSubScenario('paramA') + + // Assert + expect(result).toBe('getSubScenarioValue') + }) + + it('getAmountType', async () => { + // Arrange + cachedDb.cachePut('getAmountType', ['paramA'], 'getAmountTypeValue') + + // Act + const result = await cachedDb.getAmountType('paramA') + + // Assert + expect(result).toBe('getAmountTypeValue') + }) + + it('getPartyType', async () => { + // Arrange + cachedDb.cachePut('getPartyType', ['paramA'], 'getPartyTypeValue') + + // Act + const result = await cachedDb.getPartyType('paramA') + + // Assert + expect(result).toBe('getPartyTypeValue') + }) + + it('getPartyIdentifierType', async () => { + // Arrange + cachedDb.cachePut('getPartyIdentifierType', ['paramA'], 'getPartyIdentifierTypeValue') + + // Act + const result = await cachedDb.getPartyIdentifierType('paramA') + + // Assert + expect(result).toBe('getPartyIdentifierTypeValue') + }) + + it('getTransferParticipantRoleType', async () => { + // Arrange + cachedDb.cachePut('getTransferParticipantRoleType', ['paramA'], 'getTransferParticipantRoleTypeValue') + + // Act + const result = await cachedDb.getTransferParticipantRoleType('paramA') + + // Assert + expect(result).toBe('getTransferParticipantRoleTypeValue') + }) + + it('getLedgerEntryType', async () => { + // Arrange + cachedDb.cachePut('getLedgerEntryType', ['paramA'], 'getLedgerEntryTypeValue') + + // Act + const result = await cachedDb.getLedgerEntryType('paramA') + + // Assert + expect(result).toBe('getLedgerEntryTypeValue') + }) + }) + + describe('Cache Handling', () => { + let cachedDb + let Database + let MockCachedDatabase + + beforeEach(() => { + jest.resetModules() + + const config = new Config() + Database = require('../../../src/data/database') + MockCachedDatabase = require('../../../src/data/cachedDatabase') + + cachedDb = new MockCachedDatabase(config) + // Override the config since mocking out the superclass causes this to break + cachedDb.config = config + }) + + it('tries to get a value where none is cached', async () => { + // Arrange + // Mocking superclasses is a little tricky -- so we directly override the prototype here + Database.prototype.getLedgerEntryType = jest.fn().mockReturnValueOnce({ ledgerEntryType: true }) + const expected = { ledgerEntryType: true } + + // Act + const result = await cachedDb.getCacheValue('getLedgerEntryType', ['paramA']) + // Result should now be cached + const result2 = await cachedDb.getCacheValue('getLedgerEntryType', ['paramA']) + + // Assert + // Check that we only called the super method once, the 2nd time should be cached + expect(Database.prototype.getLedgerEntryType).toBeCalledTimes(1) + expect(result).toStrictEqual(expected) + expect(result2).toStrictEqual(expected) + }) + + it('handles an exception', async () => { + // Arrange + // Mocking superclasses is a little tricky -- so we directly override the prototype here + Database.prototype.getLedgerEntryType = jest.fn().mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => cachedDb.getCacheValue('getLedgerEntryType', ['paramA']) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) +}) diff --git a/test/unit/data/database.test.js b/test/unit/data/database.test.js new file mode 100644 index 00000000..ac371536 --- /dev/null +++ b/test/unit/data/database.test.js @@ -0,0 +1,2340 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- +******/ + +jest.mock('knex') + +const Knex = require('knex') +const crypto = require('crypto') +const ENUM = require('@mojaloop/central-services-shared').Enum + +const Database = require('../../../src/data/database') +const Config = require('../../../src/lib/config') +const LibEnum = require('../../../src/lib/enum') + +let database + +/** + * @function mockKnexBuilder + * @description Stubs out a set of Knex calls in order + * @param {Jest.Mock} rootMock - the root jest mock object to apply the mocks to + * @param {*} returnValue - the final object to be returned + * @param {*} methodList - the list of querybuilder methods that will be called + */ +const mockKnexBuilder = (rootMock, returnValue, methodList) => { + const jestMocks = [] + + const firstMock = methodList.reduceRight((acc, curr, idx) => { + jestMocks.push(acc) + const thisReturnValue = {} + thisReturnValue[curr] = acc + + if (idx === 0) { + return rootMock.mockReturnValueOnce(thisReturnValue) + } + return jest.fn().mockReturnValueOnce(thisReturnValue) + }, jest.fn().mockReturnValueOnce(returnValue)) + + // Make sure we catch the last one + jestMocks.push(firstMock) + + // Ensure the mock order matches the called order + return jestMocks.reverse() +} + +describe('/database', () => { + // Mock knex object for raw queries + const mockKnex = { + transaction: jest.fn(), + raw: jest.fn() + } + + describe('raw queries', () => { + const config = {} + + beforeEach(async () => { + jest.clearAllMocks() + + // Return the mockKnex we defined above. + // For individual tests, simply call mockKnex..mockImplementation + Knex.mockImplementation(() => mockKnex) + database = new Database(config) + await database.connect() + }) + + it('connects to knex', async () => { + expect(database.config).toStrictEqual(config) + expect(database.queryBuilder).not.toBeUndefined() + }) + + // describe('initializes a transaction', () => { + // it('returns a transaction in a promise', async () => { + // // Arrange + // mockKnex.transaction.mockReturnValueOnce('testTx') + + // // Act + // const result = await database.newTransaction() + + // // Assert + // expect(result).toBe('testTx') + // }) + // }) + + describe('isConnected', () => { + it('returns true when connected', async () => { + // Arrange + mockKnex.raw.mockReturnValueOnce(true) + + // Act + const result = await database.isConnected() + + // Assert + expect(result).toBe(true) + expect(mockKnex.raw).toHaveBeenCalledWith('SELECT 1 + 1 AS result') + }) + + it('returns false on invalid or missing result', async () => { + // Arrange + mockKnex.raw.mockReturnValueOnce(undefined) + + // Act + const result = await database.isConnected() + + // Assert + expect(result).toBe(false) + }) + + it('returns false when queryBuilder throws an error', async () => { + // Arrange + mockKnex.raw.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const result = await database.isConnected() + + // Assert + expect(result).toBe(false) + }) + }) + }) + + describe('queryBuilder queries', () => { + // Mock knex object for queryBuilder queries + const mockKnex = jest.fn() + + beforeEach(async () => { + jest.clearAllMocks() + const defaultConfig = new Config() + + // Return the mockKnex we defined above. + // For individual tests, simply call mockKnex..mockImplementation + Knex.mockImplementation(() => mockKnex) + + database = new Database(defaultConfig) + await database.connect() + }) + + describe('getTransferRules', () => { + it('gets the initiator', async () => { + // Arrange + const mockList = mockKnexBuilder( + mockKnex, + [ + { rule: '{"testRule1": true}' }, + { rule: '{"testRule2": true}' } + ], + ['where', 'select'] + ) + const expected = [ + { testRule1: true }, + { testRule2: true } + ] + + // Act + const result = await database.getTransferRules() + + // Assert + expect(result).toStrictEqual(expected) + expect(mockList[0]).toHaveBeenCalledWith('transferRules') + expect(mockList[1]).toHaveBeenCalledWith('enabled', true) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles a JSON.parse error', async () => { + // Arrange + mockKnexBuilder( + mockKnex, + [ + { rule: '{"invalidJSON: true}' } + ], + ['where', 'select'] + ) + + // Act + const action = async () => database.getTransferRules() + + // Assert + await expect(action()).rejects.toThrowError('Unexpected end of JSON input') + }) + }) + + describe('getInitiatorType', () => { + it('gets the initiator', async () => { + // Arrange + const initiatorType = 'testInitiatorType' + const mockList = mockKnexBuilder( + mockKnex, + [{ transactionInitiatorTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getInitiatorType(initiatorType) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('transactionInitiatorType') + expect(mockList[1]).toHaveBeenCalledWith('name', initiatorType) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const initiatorType = 'testInitiatorType' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getInitiatorType(initiatorType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported initiatorType \'testInitiatorType\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const initiatorType = 'testInitiatorType' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getInitiatorType(initiatorType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported initiatorType \'testInitiatorType\'') + }) + + it('handles an exception', async () => { + // Arrange + const initiatorType = 'testInitiatorType' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getInitiatorType(initiatorType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getInitiator', () => { + it('gets the initiator', async () => { + // Arrange + const initiator = 'testInitiator' + const mockList = mockKnexBuilder( + mockKnex, + [{ transactionInitiatorId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getInitiator(initiator) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('transactionInitiator') + expect(mockList[1]).toHaveBeenCalledWith('name', initiator) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const initiator = 'testInitiator' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getInitiator(initiator) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported initiator \'testInitiator\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const initiator = 'testInitiator' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getInitiator(initiator) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported initiator \'testInitiator\'') + }) + + it('handles an exception', async () => { + // Arrange + const initiator = 'testInitiator' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getInitiator(initiator) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getScenario', () => { + it('gets the scenario', async () => { + // Arrange + const scenario = 'testScenario' + const mockList = mockKnexBuilder( + mockKnex, + [{ transactionScenarioId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getScenario(scenario) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('transactionScenario') + expect(mockList[1]).toHaveBeenCalledWith('name', scenario) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const scenario = 'testScenario' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getScenario(scenario) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transaction scenario \'testScenario\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const scenario = 'testScenario' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getScenario(scenario) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transaction scenario \'testScenario\'') + }) + + it('handles an exception', async () => { + // Arrange + const scenario = 'testScenario' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getScenario(scenario) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getSubScenario', () => { + it('gets the subScenario', async () => { + // Arrange + const subScenario = 'testSubScenario' + const mockList = mockKnexBuilder( + mockKnex, + [{ transactionSubScenarioId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getSubScenario(subScenario) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('transactionSubScenario') + expect(mockList[1]).toHaveBeenCalledWith('name', subScenario) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const subScenario = 'testSubScenario' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getSubScenario(subScenario) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transaction sub-scenario \'testSubScenario\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const subScenario = 'testSubScenario' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getSubScenario(subScenario) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transaction sub-scenario \'testSubScenario\'') + }) + + it('handles an exception', async () => { + // Arrange + const subScenario = 'testSubScenario' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getSubScenario(subScenario) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getAmountType', () => { + it('gets the amountType', async () => { + // Arrange + const amountType = 'testAmountType' + const mockList = mockKnexBuilder( + mockKnex, + [{ amountTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getAmountType(amountType) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('amountType') + expect(mockList[1]).toHaveBeenCalledWith('name', amountType) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const amountType = 'testAmountType' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getAmountType(amountType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported amount type \'testAmountType\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const amountType = 'testAmountType' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getAmountType(amountType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported amount type \'testAmountType\'') + }) + + it('handles an exception', async () => { + // Arrange + const amountType = 'testAmountType' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getAmountType(amountType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createTransactionReference', () => { + it('creates a transactionReference', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const transactionReferenceId = '12345' + const mockList = mockKnexBuilder( + mockKnex, + null, + ['transacting', 'insert'] + ) + + // Act + const result = await database.createTransactionReference(txn, quoteId, transactionReferenceId) + + // Assert + expect(result).toBe(transactionReferenceId) + expect(mockList[0]).toHaveBeenCalledWith('transactionReference') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith({ + quoteId, + transactionReferenceId + }) + }) + + it('handles an exception', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const transactionReferenceId = '12345' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createTransactionReference(txn, quoteId, transactionReferenceId) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteDuplicateCheck', () => { + it('creates a quoteDuplicateCheck', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const hash = crypto.createHash('sha256').update(quoteId).digest('hex') + const mockList = mockKnexBuilder( + mockKnex, + null, + ['transacting', 'insert'] + ) + + // Act + const result = await database.createQuoteDuplicateCheck(txn, quoteId, hash) + + // Assert + expect(result).toBe(quoteId) + expect(mockList[0]).toHaveBeenCalledWith('quoteDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith({ + quoteId, + hash + }) + }) + + it('handles an exception', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const hash = crypto.createHash('sha256').update(quoteId).digest('hex') + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteDuplicateCheck(txn, quoteId, hash) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteUpdateDuplicateCheck', () => { + it('creates a quoteUpdateDuplicateCheck', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const quoteResponseId = '12345' + const hash = crypto.createHash('sha256').update(quoteId).digest('hex') + const mockList = mockKnexBuilder( + mockKnex, + null, + ['transacting', 'insert'] + ) + + // Act + const result = await database.createQuoteUpdateDuplicateCheck(txn, quoteId, quoteResponseId, hash) + + // Assert + expect(result).toBe(quoteId) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith({ + quoteId, + quoteResponseId, + hash + }) + }) + + it('handles an exception', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const quoteResponseId = '12345' + const hash = crypto.createHash('sha256').update(quoteId).digest('hex') + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteUpdateDuplicateCheck(txn, quoteId, quoteResponseId, hash) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getPartyType', () => { + it('gets the partyType', async () => { + // Arrange + const partyType = 'testPartyType' + const mockList = mockKnexBuilder( + mockKnex, + [{ partyTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getPartyType(partyType) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('partyType') + expect(mockList[1]).toHaveBeenCalledWith('name', partyType) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const partyType = 'testPartyType' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getPartyType(partyType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported party type \'testPartyType\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const partyType = 'testPartyType' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getPartyType(partyType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported party type \'testPartyType\'') + }) + + it('handles an exception', async () => { + // Arrange + const partyType = 'testPartyType' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getPartyType(partyType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getPartyIdentifierType', () => { + it('gets the partyIdentifierType', async () => { + // Arrange + const partyIdentifierType = 'testPartyIdentifierType' + const mockList = mockKnexBuilder( + mockKnex, + [{ partyIdentifierTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getPartyIdentifierType(partyIdentifierType) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('partyIdentifierType') + expect(mockList[1]).toHaveBeenCalledWith('name', partyIdentifierType) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const partyIdentifierType = 'testPartyIdentifierType' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getPartyIdentifierType(partyIdentifierType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported party identifier type \'testPartyIdentifierType\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const partyIdentifierType = 'testPartyIdentifierType' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getPartyIdentifierType(partyIdentifierType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported party identifier type \'testPartyIdentifierType\'') + }) + + it('handles an exception', async () => { + // Arrange + const partyIdentifierType = 'testPartyIdentifierType' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getPartyIdentifierType(partyIdentifierType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getParticipant', () => { + it('gets the participant for PAYEE_DFSP', async () => { + // Arrange + const participantName = 'dfsp1' + const participantType = LibEnum.PAYEE_DFSP + const currency = 'USD' + const ledgerAccountType = ENUM.Accounts.LedgerAccountType.POSITION + const mockList = mockKnexBuilder( + mockKnex, + [{ participantId: 123 }], + ['innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getParticipant(participantName, participantType, currency, ledgerAccountType) + + // Assert + expect(result).toBe(123) + expect(mockList[0]).toHaveBeenCalledWith('participant') + expect(mockList[1]).toHaveBeenCalledWith('participantCurrency', 'participantCurrency.participantId', 'participant.participantId') + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an undefined response with a participantType of PAYEE_DFSP', async () => { + // Arrange + const participantName = 'dfsp1' + const participantType = LibEnum.PAYEE_DFSP + const currency = 'USD' + const ledgerAccountType = ENUM.Accounts.LedgerAccountType.POSITION + mockKnexBuilder( + mockKnex, + undefined, + ['innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const action = async () => database.getParticipant(participantName, participantType, currency, ledgerAccountType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported participant') + }) + + it('handles an undefined response with a participantType of PAYER_DFSP', async () => { + // Arrange + const participantName = 'dfsp1' + const participantType = LibEnum.PAYER_DFSP + const currency = 'USD' + const ledgerAccountType = ENUM.Accounts.LedgerAccountType.POSITION + mockKnexBuilder( + mockKnex, + undefined, + ['innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const action = async () => database.getParticipant(participantName, participantType, currency, ledgerAccountType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported participant') + }) + + it('handles an empty response with no participantType', async () => { + // Arrange + const participantName = 'dfsp1' + const currency = 'USD' + const ledgerAccountType = ENUM.Accounts.LedgerAccountType.POSITION + mockKnexBuilder( + mockKnex, + [], + ['innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const action = async () => database.getParticipant(participantName, undefined, currency, ledgerAccountType) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported participant') + }) + }) + + describe('getTransferParticipantRoleType', () => { + it('gets the transferParticipantRoleType', async () => { + // Arrange + const name = 'testName' + const mockList = mockKnexBuilder( + mockKnex, + [{ transferParticipantRoleTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getTransferParticipantRoleType(name) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('transferParticipantRoleType') + expect(mockList[1]).toHaveBeenCalledWith({ name, isActive: 1 }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const name = 'testName' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getTransferParticipantRoleType(name) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transfer participant role type \'testName\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const name = 'testName' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getTransferParticipantRoleType(name) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported transfer participant role type \'testName\'') + }) + + it('handles an exception', async () => { + // Arrange + const name = 'name' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getTransferParticipantRoleType(name) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getLedgerEntryType', () => { + it('gets the ledgerEntityType', async () => { + // Arrange + const name = 'ledgerName' + const mockList = mockKnexBuilder( + mockKnex, + [{ ledgerEntryTypeId: 123 }], + ['where', 'select'] + ) + + // Act + const result = await database.getLedgerEntryType(name) + + // Assert + expect(result).toStrictEqual(123) + expect(mockList[0]).toHaveBeenCalledWith('ledgerEntryType') + expect(mockList[1]).toHaveBeenCalledWith({ name, isActive: 1 }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where rows is undefined', async () => { + // Arrange + const name = 'ledgerName' + mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const action = async () => database.getLedgerEntryType(name) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported ledger entry type \'ledgerName\'') + }) + + it('handles the case where rows is empty', async () => { + // Arrange + const name = 'ledgerName' + mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const action = async () => database.getLedgerEntryType(name) + + // Assert + await expect(action()).rejects.toThrowError('Unsupported ledger entry type \'ledgerName\'') + }) + + it('handles an exception', async () => { + // Arrange + const name = 'ledgerName' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getLedgerEntryType(name) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createPayerQuoteParty', () => { + it('creates a payer quote for a party', () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const party = {} + const amount = 100 + const currency = 'AUD' + database.createQuoteParty = jest.fn() + + // Act + database.createPayerQuoteParty(txn, quoteId, party, amount, currency) + + // Assert + expect(database.createQuoteParty).toHaveBeenCalledWith( + txn, + quoteId, + LibEnum.PAYER, + LibEnum.PAYER_DFSP, + LibEnum.PRINCIPLE_VALUE, + party, + 100, + 'AUD' + ) + }) + }) + + describe('createPayeeQuoteParty', () => { + it('creates a payee quote for a party', () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const party = {} + const amount = 100 + const currency = 'AUD' + database.createQuoteParty = jest.fn() + + // Act + database.createPayeeQuoteParty(txn, quoteId, party, amount, currency) + + // Assert + expect(database.createQuoteParty).toHaveBeenCalledWith( + txn, + quoteId, + LibEnum.PAYEE, + LibEnum.PAYEE_DFSP, + LibEnum.PRINCIPLE_VALUE, + party, + -100, + 'AUD' + ) + }) + }) + + describe('createQuoteParty', () => { + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = LibEnum.PAYEE + const participantType = LibEnum.PAYEE_DFSP + const ledgerEntryType = LibEnum.PRINCIPLE_VALUE + const amount = 100 + const currency = 'AUD' + const quoteParty = { + quotePartyId: 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + } + beforeEach(() => { + database.getPartyType = jest.fn().mockResolvedValueOnce('testPartyTypeId') + database.getPartyIdentifierType = jest.fn().mockResolvedValueOnce('testPartyIdentifierTypeId') + database.getParticipant = jest.fn().mockResolvedValueOnce('testParticipantId') + database.getTransferParticipantRoleType = jest.fn().mockResolvedValueOnce('testTransferParticipantRoleTypeId') + database.getLedgerEntryType = jest.fn().mockResolvedValueOnce('testLedgerEntryTypeId') + database.getTxnQuoteParty = jest.fn().mockResolvedValueOnce(quoteParty) + database.createQuotePartyIdInfoExtension = jest.fn().mockResolvedValueOnce(true) + }) + + it('Creates a quote party', async () => { + // Arrange + const txn = jest.fn() + const party = { + partyName: 'testPartyName', + partyIdInfo: { + partyIdentifier: 'testPartyIdentifier', + partyIdType: 'MSISDN', + fspId: 'payeeFsp', + extensionList: { + extension: [ + { + key: 'Test', + value: 'Data' + } + ] + } + }, + merchantClassificationCode: '0' + } + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['transacting', 'insert'] + ) + const expectedNewQuoteParty = { + quoteId, + partyTypeId: 'testPartyTypeId', + partyIdentifierTypeId: 'testPartyIdentifierTypeId', + partyIdentifierValue: 'testPartyIdentifier', + partySubIdOrTypeId: undefined, + fspId: 'payeeFsp', + participantId: 'testParticipantId', + merchantClassificationCode: '0', + partyName: 'testPartyName', + transferParticipantRoleTypeId: 'testTransferParticipantRoleTypeId', + ledgerEntryTypeId: 'testLedgerEntryTypeId', + amount: '100.0000', + currencyId: 'AUD' + } + + // Act + const result = await database.createQuoteParty(txn, quoteId, partyType, participantType, ledgerEntryType, party, amount, currency) + + // Assert + expect(result).toBe('12345') + expect(mockList[0]).toHaveBeenCalledWith('quoteParty') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedNewQuoteParty) + }) + + it('handles the partySubIdOrType', async () => { + // Arrange + const txn = jest.fn() + const party = { + partyName: 'testPartyName', + partyIdInfo: { + partySubIdOrType: 'testSubId', + partyIdentifier: 'testPartyIdentifier', + partyIdType: 'MSISDN', + fspId: 'payeeFsp' + }, + merchantClassificationCode: '0' + } + database.getPartyIdentifierType = jest.fn() + .mockResolvedValueOnce('testPartyIdentifierTypeId') + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['transacting', 'insert'] + ) + const expectedNewQuoteParty = { + quoteId, + partyTypeId: 'testPartyTypeId', + partyIdentifierTypeId: 'testPartyIdentifierTypeId', + partyIdentifierValue: 'testPartyIdentifier', + partySubIdOrTypeId: 'testSubId', + fspId: 'payeeFsp', + participantId: 'testParticipantId', + merchantClassificationCode: '0', + partyName: 'testPartyName', + transferParticipantRoleTypeId: 'testTransferParticipantRoleTypeId', + ledgerEntryTypeId: 'testLedgerEntryTypeId', + amount: '100.0000', + currencyId: 'AUD' + } + + // Act + const result = await database.createQuoteParty(txn, quoteId, partyType, participantType, ledgerEntryType, party, amount, currency) + + // Assert + expect(result).toBe('12345') + expect(mockList[0]).toHaveBeenCalledWith('quoteParty') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedNewQuoteParty) + }) + + it('creates a new party if the party contains personal info', async () => { + // Arrange + const txn = jest.fn() + const party = { + partyName: 'testPartyName', + partyIdInfo: { + partyIdentifier: 'testPartyIdentifier', + partyIdType: 'MSISDN', + fspId: 'payeeFsp' + }, + merchantClassificationCode: '0', + personalInfo: { + complexName: { + firstName: 'Mats', + middleName: 'Middle', + lastName: 'Hagman' + }, + dateOfBirth: '1983-10-25' + } + } + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['transacting', 'insert'] + ) + database.createParty = jest.fn() + const expectedNewQuoteParty = { + quoteId, + partyTypeId: 'testPartyTypeId', + partyIdentifierTypeId: 'testPartyIdentifierTypeId', + partyIdentifierValue: 'testPartyIdentifier', + partySubIdOrTypeId: undefined, + fspId: 'payeeFsp', + participantId: 'testParticipantId', + merchantClassificationCode: '0', + partyName: 'testPartyName', + transferParticipantRoleTypeId: 'testTransferParticipantRoleTypeId', + ledgerEntryTypeId: 'testLedgerEntryTypeId', + amount: '100.0000', + currencyId: 'AUD' + } + const expectedNewParty = { + firstName: 'Mats', + middleName: 'Middle', + lastName: 'Hagman', + dateOfBirth: '1983-10-25' + } + + // Act + const result = await database.createQuoteParty(txn, quoteId, partyType, participantType, ledgerEntryType, party, amount, currency) + + // Assert + expect(result).toBe('12345') + expect(mockList[0]).toHaveBeenCalledWith('quoteParty') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedNewQuoteParty) + expect(database.createParty).toHaveBeenCalledWith(txn, '12345', expectedNewParty) + }) + + it('handles an exception when creating a quote', async () => { + // Arrange + const txn = jest.fn() + const party = { + partyName: 'testPartyName', + partyIdInfo: { + partyIdentifier: 'testPartyIdentifier', + partyIdType: 'MSISDN', + fspId: 'payeeFsp' + }, + merchantClassificationCode: '0' + } + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteParty(txn, quoteId, partyType, participantType, ledgerEntryType, party, amount, currency) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getQuotePartyView', () => { + it('gets the quotePartyView', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['where', 'select'] + ) + + // Act + const result = await database.getQuotePartyView(quoteId) + + // Assert + expect(result).toStrictEqual(['12345']) + expect(mockList[0]).toHaveBeenCalledWith('quotePartyView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getQuotePartyView(quoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getQuoteView', () => { + it('gets the getQuoteView', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteView(quoteId) + + // Assert + expect(result).toStrictEqual('12345') + expect(mockList[0]).toHaveBeenCalledWith('quoteView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where the return rows are undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteView(quoteId) + + // Assert + expect(result).toStrictEqual(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where the return rows are empty', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteView(quoteId) + + // Assert + expect(result).toStrictEqual(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where there is more than 1 row', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnexBuilder( + mockKnex, + ['12345', '67890'], + ['where', 'select'] + ) + + // Act + const action = async () => database.getQuoteView(quoteId) + + // Assert + await expect(action()).rejects.toThrowError(/Expected 1 row for quoteId .*/) + }) + }) + + describe('getQuoteResponseView', () => { + it('gets the quoteResponseView', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteResponseView(quoteId) + + // Assert + expect(result).toStrictEqual('12345') + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where the return rows are undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + undefined, + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteResponseView(quoteId) + + // Assert + expect(result).toStrictEqual(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where the return rows are empty', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder( + mockKnex, + [], + ['where', 'select'] + ) + + // Act + const result = await database.getQuoteResponseView(quoteId) + + // Assert + expect(result).toStrictEqual(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseView') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles the case where there is more than 1 row', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnexBuilder( + mockKnex, + ['12345', '67890'], + ['where', 'select'] + ) + + // Act + const action = async () => database.getQuoteResponseView(quoteId) + + // Assert + await expect(action()).rejects.toThrowError(/Expected 1 row for quoteId .*/) + }) + }) + + describe('createParty', () => { + const quotePartyId = '12345' + const party = { + firstName: 'Mats', + middleName: 'Middle', + lastName: 'Hagman', + dateOfBirth: '1983-10-25' + } + + it('creates a party', async () => { + // Arrange + const txn = jest.fn() + const mockList = mockKnexBuilder( + mockKnex, + ['12345'], + ['transacting', 'insert'] + ) + const expected = { + partyId: '12345', + ...party, + quotePartyId + } + + // Act + const result = await database.createParty(txn, quotePartyId, party) + + // Assert + expect(result).toStrictEqual(expected) + expect(mockList[0]).toHaveBeenCalledWith('party') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception when creating a party', async () => { + // Arrange + const txn = jest.fn() + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createParty(txn, quotePartyId, party) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuote', () => { + const mockQuote = { + quoteId: 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37', + transactionReferenceId: 'referenceId', + transactionRequestId: 'abc123', + note: 'test quote', + expirationDate: '2019-10-30T10:30:19.899Z', + transactionInitiatorId: 'CONSUMER', + transactionInitiatorTypeId: 'payee', + transactionScenarioId: 'TRANSFER', + balanceOfPaymentsId: '1', + transactionSubScenarioId: 'testSubScenario', + amountTypeId: 'SEND', + amount: 100, + currencyId: 'USD' + } + + it('creates a quote', async () => { + // Arrange + const txn = jest.fn() + const mockList = mockKnexBuilder( + mockKnex, + null, + ['transacting', 'insert'] + ) + const expectedInsert = { + ...mockQuote, + amount: '100.0000' + } + + // Act + const result = await database.createQuote(txn, mockQuote) + + // Assert + expect(result).toEqual(mockQuote.quoteId) + expect(mockList[0]).toHaveBeenCalledWith('quote') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedInsert) + }) + + it('handles an error creating the quote', async () => { + // Arrange + const txn = jest.fn() + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuote(txn, mockQuote) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuotePartyIdInfoExtension', () => { + const mockQuotePartyIdInfoExtension = { + quotePartyId: 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37', + key: 'Test', + value: 'data' + } + const extensionList = { + key: 'Test', + value: 'data' + } + const quoteParty = { + quotePartyId: 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + } + + it('creates a quote partyId info extension', async () => { + // Arrange + const txn = jest.fn() + const mockList = mockKnexBuilder( + mockKnex, + null, + ['transacting', 'insert'] + ) + const expectedInsert = { + ...mockQuotePartyIdInfoExtension + } + + // Act + const result = await database.createQuotePartyIdInfoExtension(txn, extensionList, quoteParty) + + // Assert + expect(result).toEqual(true) + expect(mockList[0]).toHaveBeenCalledWith('quotePartyIdInfoExtension') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedInsert) + }) + + it('handles an error creating the quote', async () => { + // Arrange + const txn = jest.fn() + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuotePartyIdInfoExtension(txn, extensionList, quoteParty) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getQuoteParty', () => { + it('gets the quote party', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + const mockList = mockKnexBuilder( + mockKnex, + [{ value: 'mockQuoteParty' }], + ['innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuoteParty(quoteId, partyType) + + // Assert + expect(result).toStrictEqual({ value: 'mockQuoteParty' }) + expect(mockList[0]).toHaveBeenCalledWith('quoteParty') + expect(mockList[1]).toHaveBeenCalledWith('partyType', 'partyType.partyTypeId', 'quoteParty.partyTypeId') + expect(mockList[2]).toHaveBeenCalledWith('quoteParty.quoteId', quoteId) + expect(mockList[3]).toHaveBeenCalledWith('partyType.name', partyType) + expect(mockList[4]).toHaveBeenCalledWith('quoteParty.*') + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + undefined, + ['innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuoteParty(quoteId, partyType) + + // Assert + expect(result).toStrictEqual(null) + }) + + it('returns null when the query returns no rows', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + [], + ['innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuoteParty(quoteId, partyType) + + // Assert + expect(result).toStrictEqual(null) + }) + + it('handles an exception', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getQuoteParty(quoteId, partyType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + + it('throws an exception when more than one quoteParty is found', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + [{ value: 'mockQuoteParty' }, { value: 'mockQuoteParty2' }], + ['innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const action = async () => database.getQuoteParty(quoteId, partyType) + + // Assert + await expect(action()).rejects.toThrowError(/Expected 1 quoteParty .*/) + }) + }) + + describe('getTxnQuoteParty', () => { + it('gets the txn quote party', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + const mockList = mockKnexBuilder( + mockKnex, + [{ value: 'mockQuoteParty' }], + ['transacting', 'innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getTxnQuoteParty(txn, quoteId, partyType) + + // Assert + expect(result).toStrictEqual({ value: 'mockQuoteParty' }) + expect(mockList[0]).toHaveBeenCalledWith('quoteParty') + expect(mockList[2]).toHaveBeenCalledWith('partyType', 'partyType.partyTypeId', 'quoteParty.partyTypeId') + expect(mockList[3]).toHaveBeenCalledWith('quoteParty.quoteId', quoteId) + expect(mockList[4]).toHaveBeenCalledWith('partyType.name', partyType) + expect(mockList[5]).toHaveBeenCalledWith('quoteParty.*') + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + undefined, + ['transacting', 'innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getTxnQuoteParty(txn, quoteId, partyType) + + // Assert + expect(result).toStrictEqual(null) + }) + + it('returns null when the query returns no rows', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + [], + ['transacting', 'innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const result = await database.getTxnQuoteParty(txn, quoteId, partyType) + + // Assert + expect(result).toStrictEqual(null) + }) + + it('handles an exception', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getTxnQuoteParty(txn, quoteId, partyType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + + it('throws an exception when more than one quoteParty is found', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const partyType = 'PAYEE' + mockKnexBuilder( + mockKnex, + [{ value: 'mockQuoteParty' }, { value: 'mockQuoteParty2' }], + ['transacting', 'innerJoin', 'where', 'andWhere', 'select'] + ) + + // Act + const action = async () => database.getTxnQuoteParty(txn, quoteId, partyType) + + // Assert + await expect(action()).rejects.toThrowError(/Expected 1 quoteParty .*/) + }) + }) + + describe('getQuotePartyEndpoint', () => { + it('gets the quote party endpoint', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + const partyType = 'PAYEE' + const mockList = mockKnexBuilder( + mockKnex, + [{ value: 'http://localhost:3000/testEndpoint' }], + ['innerJoin', 'innerJoin', 'innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuotePartyEndpoint(quoteId, endpointType, partyType) + + // Assert + expect(result).toBe('http://localhost:3000/testEndpoint') + expect(mockList[0]).toHaveBeenCalledWith('participantEndpoint') + expect(mockList[1]).toHaveBeenCalledWith('endpointType', 'participantEndpoint.endpointTypeId', 'endpointType.endpointTypeId') + expect(mockList[2]).toHaveBeenCalledWith('quoteParty', 'quoteParty.participantId', 'participantEndpoint.participantId') + expect(mockList[3]).toHaveBeenCalledWith('partyType', 'partyType.partyTypeId', 'quoteParty.partyTypeId') + expect(mockList[4]).toHaveBeenCalledWith('quote', 'quote.quoteId', 'quoteParty.quoteId') + expect(mockList[5]).toHaveBeenCalledWith('endpointType.name', endpointType) + expect(mockList[6]).toHaveBeenCalledWith('partyType.name', partyType) + expect(mockList[7]).toHaveBeenCalledWith('quote.quoteId', quoteId) + expect(mockList[8]).toHaveBeenCalledWith('participantEndpoint.isActive', 1) + expect(mockList[9]).toHaveBeenCalledWith('participantEndpoint.value') + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnexBuilder( + mockKnex, + undefined, + ['innerJoin', 'innerJoin', 'innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuotePartyEndpoint(participantName, endpointType) + + // Assert + expect(result).toBe(null) + }) + + it('returns null when there are no rows found', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnexBuilder( + mockKnex, + [], + ['innerJoin', 'innerJoin', 'innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getQuotePartyEndpoint(participantName, endpointType) + + // Assert + expect(result).toBe(null) + }) + + it('handles an exception', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getQuotePartyEndpoint(participantName, endpointType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getParticipantEndpoint', () => { + it('gets the participant endpoint', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + const mockList = mockKnexBuilder( + mockKnex, + [{ value: 'http://localhost:3000/testEndpoint' }], + ['innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getParticipantEndpoint(participantName, endpointType) + + // Assert + expect(result).toBe('http://localhost:3000/testEndpoint') + expect(mockList[0]).toBeCalledWith('participantEndpoint') + expect(mockList[1]).toBeCalledWith('participant', 'participant.participantId', 'participantEndpoint.participantId') + expect(mockList[2]).toBeCalledWith('endpointType', 'endpointType.endpointTypeId', 'participantEndpoint.endpointTypeId') + expect(mockList[3]).toBeCalledWith('participant.name', participantName) + expect(mockList[4]).toBeCalledWith('endpointType.name', endpointType) + expect(mockList[5]).toBeCalledWith('participantEndpoint.isActive', 1) + expect(mockList[6]).toBeCalledWith('participantEndpoint.value') + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnexBuilder( + mockKnex, + undefined, + ['innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getParticipantEndpoint(participantName, endpointType) + + // Assert + expect(result).toBe(null) + }) + + it('returns null when there are no rows found', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnexBuilder( + mockKnex, + [], + ['innerJoin', 'innerJoin', 'where', 'andWhere', 'andWhere', 'select'] + ) + + // Act + const result = await database.getParticipantEndpoint(participantName, endpointType) + + // Assert + expect(result).toBe(null) + }) + + it('handles an exception', async () => { + // Arrange + const participantName = 'fsp1' + const endpointType = 'FSPIOP_CALLBACK_URL_QUOTES' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getParticipantEndpoint(participantName, endpointType) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getQuoteDuplicateCheck', () => { + it('gets the getQuoteDuplicateCheck', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, ['1'], ['where', 'select']) + + // Act + const result = await database.getQuoteDuplicateCheck(quoteId) + + // Assert + expect(result).toBe('1') + expect(mockList[0]).toHaveBeenCalledWith('quoteDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, null, ['where', 'select']) + + // Act + const result = await database.getQuoteDuplicateCheck(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when there are no rows found', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, [], ['where', 'select']) + + // Act + const result = await database.getQuoteDuplicateCheck(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getQuoteDuplicateCheck(quoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getQuoteResponseDuplicateCheck', () => { + it('gets the quoteResponseDuplicateCheck', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, ['1'], ['where', 'select']) + + // Act + const result = await database.getQuoteResponseDuplicateCheck(quoteId) + + // Assert + expect(result).toBe('1') + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, undefined, ['where', 'select']) + + // Act + const result = await database.getQuoteResponseDuplicateCheck(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when there are no rows found', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, [], ['where', 'select']) + + // Act + const result = await database.getQuoteResponseDuplicateCheck(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseDuplicateCheck') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getQuoteResponseDuplicateCheck(quoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getTransactionReference', () => { + it('gets the transaction reference', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, ['1'], ['where', 'select']) + + // Act + const result = await database.getTransactionReference(quoteId) + + // Assert + expect(result).toBe('1') + expect(mockList[0]).toHaveBeenCalledWith('transactionReference') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when the query returns undefined', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, undefined, ['where', 'select']) + + // Act + const result = await database.getTransactionReference(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('transactionReference') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('returns null when there are no rows found', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, [], ['where', 'select']) + + // Act + const result = await database.getTransactionReference(quoteId) + + // Assert + expect(result).toBe(null) + expect(mockList[0]).toHaveBeenCalledWith('transactionReference') + expect(mockList[1]).toHaveBeenCalledWith({ quoteId }) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception', async () => { + // Arrange + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.getTransactionReference(quoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteResponse', () => { + const completeQuoteResponse = { + transferAmount: { + amount: '100', + currency: 'USD' + }, + payeeReceiveAmount: { + amount: '99', + currency: 'USD' + }, + payeeFspFee: { + amount: '1', + currency: 'USD' + }, + payeeFspCommission: { + amount: '1', + currency: 'USD' + }, + condition: 'HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks', + expiration: '2019-05-27T15:44:53.292Z', + isValid: true + } + + it('creates the quote response', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + const mockList = mockKnexBuilder(mockKnex, ['1'], ['transacting', 'insert']) + const expected = { + quoteId, + quoteResponseId: '1', + ilpCondition: completeQuoteResponse.condition, + isValid: completeQuoteResponse.isValid, + payeeFspCommissionAmount: '1.0000', + payeeFspCommissionCurrencyId: 'USD', + payeeFspFeeAmount: '1.0000', + payeeFspFeeCurrencyId: 'USD', + payeeReceiveAmount: '99.0000', + payeeReceiveAmountCurrencyId: 'USD', + responseExpirationDate: '2019-05-27T15:44:53.292Z', + transferAmount: '100.0000', + transferAmountCurrencyId: 'USD' + } + + // Act + const result = await database.createQuoteResponse(txn, quoteId, completeQuoteResponse) + + // Assert + expect(result).toStrictEqual(expected) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponse') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception in createQuoteResponse', async () => { + // Arrange + const txn = jest.fn() + const quoteId = 'ddaa67b3-5bf8-45c1-bfcf-1e8781177c37' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteResponse(txn, quoteId, completeQuoteResponse) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteResponseIlpPacket', () => { + it('creates a new createQuoteResponseIlpPacket', async () => { + // Arrange + const txn = jest.fn() + const quoteResponseId = '12345' + const ilpPacket = 'mock_ilp_packet' + const mockList = mockKnexBuilder(mockKnex, ['12345'], ['transacting', 'insert']) + const expectedInsert = { + quoteResponseId, + value: ilpPacket + } + + // Act + const result = await database.createQuoteResponseIlpPacket(txn, quoteResponseId, ilpPacket) + + // Assert + expect(result).toStrictEqual(['12345']) + expect(mockList[0]).toHaveBeenCalledWith('quoteResponseIlpPacket') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(expectedInsert) + }) + + it('handles an exception in creating the GeoCode', async () => { + // Arrange + const txn = jest.fn() + const quoteResponseId = '12345' + const ilpPacket = 'mock_ilp_packet' + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteResponseIlpPacket(txn, quoteResponseId, ilpPacket) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createGeoCode', () => { + it('creates a new GeoCode', async () => { + // Arrange + const txn = jest.fn() + const geoCode = { + quotePartyId: '12345', + latitude: '00.0000', + longitude: '00.0000' + } + const mockList = mockKnexBuilder(mockKnex, ['12345'], ['transacting', 'insert']) + + // Act + const result = await database.createGeoCode(txn, geoCode) + + // Assert + expect(result).toStrictEqual(['12345']) + expect(mockList[0]).toHaveBeenCalledWith('geoCode') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception in creating the GeoCode', async () => { + // Arrange + const txn = jest.fn() + const geoCode = { + quotePartyId: '12345', + latitude: '00.0000', + longitude: '00.0000' + } + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createGeoCode(txn, geoCode) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteExtensions', () => { + it('creates new quoteExtensions', async () => { + // Arrange + const txn = jest.fn() + const extensions = [{ + key: 'key1', + value: 'value1' + }, { + key: 'key2', + value: 'value2' + }] + const quoteId = '123' + const transactionId = '789' + const quoteResponseId = 456 + + const mockList = mockKnexBuilder(mockKnex, ['12345'], ['transacting', 'insert']) + + // Act + const result = await database.createQuoteExtensions(txn, extensions, quoteId, transactionId, quoteResponseId) + + // Assert + expect(result).toStrictEqual(['12345']) + expect(mockList[0]).toHaveBeenCalledWith('quoteExtension') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledWith(extensions.map(({ key, value }) => ({ + key, value, quoteId, transactionId, quoteResponseId + }))) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception in creating the quoteExtensions', async () => { + // Arrange + const txn = jest.fn() + const extensions = [{ + quoteId: '123', + quoteResponseId: 456, + key: 'key1', + value: 'value1' + }, { + quoteId: '789', + quoteResponseId: 101112, + key: 'key2', + value: 'value2' + }] + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteExtensions(txn, extensions) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('createQuoteError', () => { + it('creates a default quote error', async () => { + // Arrange + const txn = jest.fn() + const error = { + quoteId: '12345', + errorCode: '2201', + errorDescription: 'Test Error' + } + const mockList = mockKnexBuilder(mockKnex, ['12345'], ['transacting', 'insert']) + + // Act + const result = await database.createQuoteError(txn, error) + + // Assert + expect(result).toStrictEqual(['12345']) + expect(mockList[0]).toHaveBeenCalledWith('quoteError') + expect(mockList[1]).toHaveBeenCalledWith(txn) + expect(mockList[2]).toHaveBeenCalledTimes(1) + }) + + it('handles an exception in handling the quote error', async () => { + // Arrange + const txn = jest.fn() + const error = { + quoteId: '12345', + errorCode: '2201', + errorDescription: 'Test Error' + } + mockKnex.mockImplementationOnce(() => { throw new Error('Test Error') }) + + // Act + const action = async () => database.createQuoteError(txn, error) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + }) + + describe('getIsMigrationLocked', () => { + it('gets the migration lock status when the database is locked', async () => { + // Arrange + const mockList = mockKnexBuilder(mockKnex, { isLocked: true }, ['orderBy', 'first', 'select']) + + // Act + const result = await database.getIsMigrationLocked() + + // Assert + expect(result).toBe(true) + expect(mockList[0]).toHaveBeenCalledWith('migration_lock') + expect(mockList[1]).toHaveBeenCalledWith('index', 'desc') + expect(mockList[2]).toHaveBeenCalledTimes(1) + expect(mockList[3]).toHaveBeenCalledWith('is_locked AS isLocked') + }) + }) + }) +}) diff --git a/test/unit/handlers/bulkQuotes.test.js b/test/unit/handlers/bulkQuotes.test.js new file mode 100644 index 00000000..94f236d2 --- /dev/null +++ b/test/unit/handlers/bulkQuotes.test.js @@ -0,0 +1,112 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + + * Modusbox + - Rajiv Mothilal + -------------- + ******/ +jest.mock('../../../src/model/bulkQuotes') + +const Enum = require('@mojaloop/central-services-shared').Enum + +const BulkQuotesModel = require('../../../src/model/bulkQuotes') +const BulkQuotesHandler = require('../../../src/handlers/bulkQuotes') +const { baseMockRequest } = require('../../util/helper') + +const mockContext = jest.fn() + +describe('/bulkQuotes', () => { + describe('POST', () => { + beforeEach(() => { + BulkQuotesModel.mockClear() + }) + + it('creates a bulkQuote', async () => { + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + const mockRequest = { + ...baseMockRequest, + payload: { + quoteId: '12345' + }, + span: { + audit: jest.fn(), + setTags: jest.fn() + } + } + + // Act + await BulkQuotesHandler.post(mockContext, mockRequest, handler) + + // Assert + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + const mockQuoteInstance = BulkQuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleBulkQuoteRequest).toHaveBeenCalledTimes(1) + }) + + it('fails to create a quote', async () => { + // Arrange + const handleException = jest.fn() + BulkQuotesModel.mockImplementationOnce(() => ({ + handleBulkQuoteRequest: () => { + throw new Error('Create Quote Test Error') + }, + handleException + })) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + const mockRequest = { + ...baseMockRequest, + payload: { + bulkQuoteId: '12345' + }, + span: { + audit: jest.fn(), + setTags: jest.fn() + } + } + + // Act + await BulkQuotesHandler.post(mockContext, mockRequest, handler) + + // Assert + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + expect(handleException).toHaveBeenCalledTimes(1) + }) + }) +}) diff --git a/test/unit/handlers/bulkQuotes/{id}.test.js b/test/unit/handlers/bulkQuotes/{id}.test.js new file mode 100644 index 00000000..b75b261a --- /dev/null +++ b/test/unit/handlers/bulkQuotes/{id}.test.js @@ -0,0 +1,147 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + + * Modusbox + - Rajiv Mothilal + -------------- + ******/ + +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../../src/model/bulkQuotes') + +const Enum = require('@mojaloop/central-services-shared').Enum +const BulkQuotesHandler = require('../../../../src/handlers/bulkQuotes/{id}') +const BulkQuotesModel = require('../../../../src/model/bulkQuotes') +const { baseMockRequest } = require('../../../util/helper') + +const mockContext = jest.fn() + +describe('/bulkQuotes/{id}', () => { + beforeEach(() => { + BulkQuotesModel.mockClear() + }) + + describe('GET', () => { + it('gets a bulk quote by id', async () => { + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesHandler.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = BulkQuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleBulkQuoteGet).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const handleException = jest.fn() + BulkQuotesModel.mockImplementationOnce(() => { + return { + handleBulkQuoteGet: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesHandler.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + }) + }) + + describe('PUT', () => { + it('puts a bulk quote by id', async () => { + BulkQuotesModel.mockClear() + + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesHandler.put(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = BulkQuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleBulkQuoteUpdate).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const handleException = jest.fn() + BulkQuotesModel.mockImplementationOnce(() => { + return { + handleBulkQuoteUpdate: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesHandler.put(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + }) +}) diff --git a/test/unit/handlers/bulkQuotes/{id}/error.test.js b/test/unit/handlers/bulkQuotes/{id}/error.test.js new file mode 100644 index 00000000..d68c3cad --- /dev/null +++ b/test/unit/handlers/bulkQuotes/{id}/error.test.js @@ -0,0 +1,113 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +const Enum = require('@mojaloop/central-services-shared').Enum + +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../../../src/model/bulkQuotes') + +const BulkQuotesErrorHandler = require('../../../../../src/handlers/bulkQuotes/{id}/error') +const BulkQuotesModel = require('../../../../../src/model/bulkQuotes') +const { baseMockRequest } = require('../../../../util/helper') + +const mockContext = jest.fn() + +describe('/bulkQuotes/{id}/error', () => { + beforeEach(() => { + BulkQuotesModel.mockClear() + }) + + describe('PUT', () => { + it('handles an error', async () => { + // Arrange + const request = { + ...baseMockRequest, + payload: { + errorInformation: { + errorCode: '2201', + errorDescription: 'Test Error' + } + } + } + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesErrorHandler.put(mockContext, request, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = BulkQuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleBulkQuoteError).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const request = { + ...baseMockRequest, + payload: { + errorInformation: { + errorCode: '2201', + errorDescription: 'Test Error' + } + } + } + const handleException = jest.fn() + BulkQuotesModel.mockImplementationOnce(() => { + return { + handleBulkQuoteError: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await BulkQuotesErrorHandler.put(mockContext, request, handler) + + // Assert + expect(BulkQuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + }) +}) diff --git a/test/unit/handlers/health.test.js b/test/unit/handlers/health.test.js new file mode 100644 index 00000000..ee775fa4 --- /dev/null +++ b/test/unit/handlers/health.test.js @@ -0,0 +1,204 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ +jest.mock('../../../src/lib/config') + +const { responseCode, statusEnum } = require('@mojaloop/central-services-shared').HealthCheck.HealthCheckEnums +const HealthHandler = require('../../../src/handlers/health') +const { baseMockRequest } = require('../../util/helper') + +let Config = require('../../../src/lib/config') +let HealthCheck = require('@mojaloop/central-services-shared/src/healthCheck') + +const mockContext = jest.fn() + +describe('/health', () => { + describe('getSubServiceHealthDatastore', () => { + beforeAll(() => { + jest.mock('@mojaloop/central-services-shared/src/healthCheck') + }) + + it('is down when the database throws an error', async () => { + // Arrange + const mockDb = { + getIsMigrationLocked: jest.fn(() => { throw new Error('Test Error') }) + } + + // Act + const result = await HealthHandler.getSubServiceHealthDatastore(mockDb) + + // Assert + expect(result.status).toEqual(statusEnum.DOWN) + }) + + it('is down when the database is locked', async () => { + // Arrange + const mockDb = { + getIsMigrationLocked: jest.fn(() => true) + } + + // Act + const result = await HealthHandler.getSubServiceHealthDatastore(mockDb) + + // Assert + expect(result.status).toEqual(statusEnum.DOWN) + }) + + it('is up when the database is not locked', async () => { + // Arrange + const mockDb = { + getIsMigrationLocked: jest.fn(() => false) + } + + // Act + const result = await HealthHandler.getSubServiceHealthDatastore(mockDb) + + // Assert + expect(result.status).toEqual(statusEnum.OK) + }) + }) + + describe('GET success', () => { + let code + let handler + + beforeEach(() => { + // We need to reimport the modules here, since `new Config()` is called at import time + jest.resetModules() + jest.mock('@mojaloop/central-services-shared/src/healthCheck') + Config = require('../../../src/lib/config') + HealthCheck = require('@mojaloop/central-services-shared/src/healthCheck').HealthCheck + + handler = { + response: jest.fn(() => ({ + code + })) + } + HealthCheck.mockImplementationOnce(() => ({ + getHealth: () => ({ + status: statusEnum.OK + }) + })) + }) + + it('returns an UP response when simpleRoutingMode is on', async () => { + // Arrange + code = jest.fn() + Config.mockImplementation(() => ({ + simpleRoutingMode: true + })) + const HealthHandlerProxy = require('../../../src/handlers/health') + const expectedServiceHealthList = [] + + // Act + await HealthHandlerProxy.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(code).toHaveBeenCalledWith(responseCode.success) + expect(HealthCheck.mock.calls.pop()[1]).toEqual(expectedServiceHealthList) + }) + + it('returns an UP response when simpleRoutingMode is off', async () => { + // Arrange + code = jest.fn() + Config.mockImplementation(() => ({ + simpleRoutingMode: false + })) + const HealthHandlerProxy = require('../../../src/handlers/health') + + // Act + await HealthHandlerProxy.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(code).toHaveBeenCalledWith(responseCode.success) + // Ensure there was one item in the `serviceHealthList` + expect(HealthCheck.mock.calls.pop()[1].length).toEqual(1) + }) + }) + + describe('GET failure', () => { + let code + let handler + let HealthHandlerProxy + + beforeEach(() => { + // We need to reimport the modules here, since `new Config()` is called at import time + jest.resetModules() + Config = require('../../../src/lib/config') + Config.mockImplementation(() => ({ + simpleRoutingMode: false + })) + + handler = { + response: jest.fn(() => ({ + code + })) + } + }) + + it('returns an down response when getHealth returns DOWN', async () => { + // Arrange + HealthCheck = require('@mojaloop/central-services-shared/src/healthCheck').HealthCheck + HealthHandlerProxy = require('../../../src/handlers/health') + + code = jest.fn() + const mockRequest = { + ...baseMockRequest + } + mockRequest.server.app.database.getIsMigrationLocked = jest.fn().mockImplementation(() => { + throw new Error('Test Error') + }) + + // Act + await HealthHandlerProxy.get(mockContext, mockRequest, handler) + + // Assert + expect(code).toHaveBeenCalledWith(responseCode.gatewayTimeout) + }) + + it('returns an down response when getHealth returns undefined', async () => { + // Arrange + jest.mock('@mojaloop/central-services-shared/src/healthCheck') + HealthCheck = require('@mojaloop/central-services-shared/src/healthCheck').HealthCheck + HealthHandlerProxy = require('../../../src/handlers/health') + + code = jest.fn() + HealthCheck.mockImplementationOnce(() => ({ + getHealth: () => undefined + })) + + // Act + await HealthHandlerProxy.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(code).toHaveBeenCalledWith(responseCode.gatewayTimeout) + }) + }) +}) diff --git a/test/unit/handlers/quotes.test.js b/test/unit/handlers/quotes.test.js new file mode 100644 index 00000000..320d2468 --- /dev/null +++ b/test/unit/handlers/quotes.test.js @@ -0,0 +1,110 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +jest.mock('../../../src/model/quotes') + +const Enum = require('@mojaloop/central-services-shared').Enum + +const QuotesModel = require('../../../src/model/quotes') +const QuotesHandler = require('../../../src/handlers/quotes') +const { baseMockRequest } = require('../../util/helper') + +const mockContext = jest.fn() + +describe('/quotes', () => { + describe('POST', () => { + beforeEach(() => { + QuotesModel.mockClear() + }) + + it('creates a quote', async () => { + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + const mockRequest = { + ...baseMockRequest, + payload: { + quoteId: '12345' + }, + span: { + audit: jest.fn(), + setTags: jest.fn() + } + } + + // Act + await QuotesHandler.post(mockContext, mockRequest, handler) + + // Assert + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + const mockQuoteInstance = QuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleQuoteRequest).toHaveBeenCalledTimes(1) + }) + + it('fails to create a quote', async () => { + // Arrange + const handleException = jest.fn(() => ({ code: Enum.Http.ReturnCodes.ACCEPTED.CODE })) + QuotesModel.mockImplementationOnce(() => ({ + handleQuoteRequest: () => { + throw new Error('Create Quote Test Error') + }, + handleException + })) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + const mockRequest = { + ...baseMockRequest, + payload: { + quoteId: '12345' + }, + span: { + audit: jest.fn(), + setTags: jest.fn() + } + } + + // Act + await QuotesHandler.post(mockContext, mockRequest, handler) + + // Assert + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + expect(handleException).toHaveBeenCalledTimes(1) + }) + }) +}) diff --git a/test/unit/handlers/quotes/{id}.test.js b/test/unit/handlers/quotes/{id}.test.js new file mode 100644 index 00000000..d926a902 --- /dev/null +++ b/test/unit/handlers/quotes/{id}.test.js @@ -0,0 +1,144 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../../src/model/quotes') + +const Enum = require('@mojaloop/central-services-shared').Enum +const QuotesHandler = require('../../../../src/handlers/quotes/{id}') +const QuotesModel = require('../../../../src/model/quotes') +const { baseMockRequest } = require('../../../util/helper') + +const mockContext = jest.fn() + +describe('/quotes/{id}', () => { + beforeEach(() => { + QuotesModel.mockClear() + }) + + describe('GET', () => { + it('gets a quote by id', async () => { + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesHandler.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = QuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleQuoteGet).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const handleException = jest.fn(() => ({ code: Enum.Http.ReturnCodes.ACCEPTED.CODE })) + QuotesModel.mockImplementationOnce(() => { + return { + handleQuoteGet: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesHandler.get(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.ACCEPTED.CODE) + }) + }) + + describe('PUT', () => { + it('puts a quote by id', async () => { + QuotesModel.mockClear() + + // Arrange + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesHandler.put(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = QuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleQuoteUpdate).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const handleException = jest.fn(() => ({ code: Enum.Http.ReturnCodes.ACCEPTED.CODE })) + QuotesModel.mockImplementationOnce(() => { + return { + handleQuoteUpdate: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesHandler.put(mockContext, { ...baseMockRequest }, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + }) +}) diff --git a/test/unit/handlers/quotes/{id}/error.test.js b/test/unit/handlers/quotes/{id}/error.test.js new file mode 100644 index 00000000..8ea2a50c --- /dev/null +++ b/test/unit/handlers/quotes/{id}/error.test.js @@ -0,0 +1,113 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +const Enum = require('@mojaloop/central-services-shared').Enum + +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../../../src/model/quotes') + +const QuotesErrorHandler = require('../../../../../src/handlers/quotes/{id}/error') +const QuotesModel = require('../../../../../src/model/quotes') +const { baseMockRequest } = require('../../../../util/helper') + +const mockContext = jest.fn() + +describe('/quotes/{id}', () => { + beforeEach(() => { + QuotesModel.mockClear() + }) + + describe('PUT', () => { + it('handles an error', async () => { + // Arrange + const request = { + ...baseMockRequest, + payload: { + errorInformation: { + errorCode: '2201', + errorDescription: 'Test Error' + } + } + } + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesErrorHandler.put(mockContext, request, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + const mockQuoteInstance = QuotesModel.mock.instances[0] + expect(mockQuoteInstance.handleQuoteError).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + + it('handles an error with the model', async () => { + // Arrange + const request = { + ...baseMockRequest, + payload: { + errorInformation: { + errorCode: '2201', + errorDescription: 'Test Error' + } + } + } + const handleException = jest.fn(() => ({ code: Enum.Http.ReturnCodes.OK.CODE })) + QuotesModel.mockImplementationOnce(() => { + return { + handleQuoteError: () => { + throw new Error('Test error') + }, + handleException + } + }) + const code = jest.fn() + const handler = { + response: jest.fn(() => ({ + code + })) + } + + // Act + await QuotesErrorHandler.put(mockContext, request, handler) + + // Assert + expect(QuotesModel).toHaveBeenCalledTimes(1) + expect(handleException).toHaveBeenCalledTimes(1) + expect(code).toHaveBeenCalledWith(Enum.Http.ReturnCodes.OK.CODE) + }) + }) +}) diff --git a/test/unit/lib/config.test.js b/test/unit/lib/config.test.js new file mode 100644 index 00000000..480925de --- /dev/null +++ b/test/unit/lib/config.test.js @@ -0,0 +1,115 @@ + +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + + * Crosslake + - Lewis Daly + + -------------- + ******/ +'use strict' + +const mockDefaultFile = { + HOSTNAME: 'http://quoting-service', + LISTEN_ADDRESS: '0.0.0.0', + PORT: 3002, + AMOUNT: { + PRECISION: 18, + SCALE: 4 + }, + DATABASE: { + DIALECT: 'mysql', + HOST: 'localhost', + PORT: 3306, + USER: 'central_ledger', + PASSWORD: 'password', + SCHEMA: 'central_ledger', + POOL_MIN_SIZE: 10, + POOL_MAX_SIZE: 10, + ACQUIRE_TIMEOUT_MILLIS: 30000, + CREATE_TIMEOUT_MILLIS: 30000, + DESTROY_TIMEOUT_MILLIS: 5000, + IDLE_TIMEOUT_MILLIS: 30000, + REAP_INTERVAL_MILLIS: 1000, + CREATE_RETRY_INTERVAL_MILLIS: 200, + DEBUG: true + }, + SWITCH_ENDPOINT: 'http://localhost:3001', + ERROR_HANDLING: { + includeCauseExtension: false, + truncateExtensions: true + }, + SIMPLE_ROUTING_MODE: true, + ENDPOINT_SECURITY: { + JWS: { + JWS_SIGN: true, + FSPIOP_SOURCE_TO_SIGN: 'switch', + JWS_SIGNING_KEY_PATH: 'secrets/jwsSigningKey.key' + } + } +} + +describe('Config', () => { + beforeEach(() => { + jest.resetModules() + }) + + it('sets the default amounts', () => { + // Arrange + jest.mock('../../../config/default.json', () => ({ + ...mockDefaultFile, + AMOUNT: {} + }), { virtual: true }) + + const Config = require('../../../src/lib/config') + + // Act + const result = new Config() + + // Assert + expect(result.amount.precision).toBe(18) + expect(result.amount.scale).toBe(4) + expect(result.database.debug).toBe(true) + }) + + it('throws when JWS Signing key file is not provided', () => { + // Arrange + jest.mock('../../../config/default.json', () => ({ + ...mockDefaultFile, + ENDPOINT_SECURITY: { + JWS: { + JWS_SIGN: true, + FSPIOP_SOURCE_TO_SIGN: 'switch', + JWS_SIGNING_KEY_PATH: '/fake/path' + } + } + }), { virtual: true }) + + const Config = require('../../../src/lib/config') + + // Act + try { + const result = new Config() + expect(result).toBeUndefined() + } catch (error) { + expect(error).toBeInstanceOf(Error) + expect(error).toHaveProperty('message', 'File /fake/path doesn\'t exist, can\'t enable JWS signing') + } + }) +}) diff --git a/test/unit/lib/http.test.js b/test/unit/lib/http.test.js new file mode 100644 index 00000000..4d611961 --- /dev/null +++ b/test/unit/lib/http.test.js @@ -0,0 +1,80 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + + * Crosslake + - Lewis Daly + + -------------- + ******/ +'use strict' + +jest.mock('axios') + +const axios = require('axios') +const { httpRequest } = require('../../../src/lib/http') + +describe('httpRequest', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it('performs a successful http request', async () => { + // Arrange + axios.request.mockReturnValueOnce({ + status: 200, + data: Promise.resolve({}) + }) + const options = {} + + // Act + await httpRequest(options, 'payeefsp') + + // Assert + expect(axios.request).toHaveBeenCalledTimes(1) + }) + + it('handles a http exception', async () => { + // Arrange + axios.request.mockImplementationOnce(() => { throw new Error('Network error') }) + const options = {} + + // Act + const action = async () => httpRequest(options, 'payeefsp') + + // Assert + await expect(action()).rejects.toThrow('Network error') + expect(axios.request).toHaveBeenCalledTimes(1) + }) + + it('handles a bad response', async () => { + // Arrange + axios.request.mockReturnValueOnce({ + status: 400, + data: Promise.resolve({}) + }) + const options = {} + + // Act + const action = async () => httpRequest(options, 'payeefsp') + + // Assert + await expect(action()).rejects.toThrow('Non-success response in HTTP request') + expect(axios.request).toHaveBeenCalledTimes(1) + }) +}) diff --git a/test/unit/lib/util.test.js b/test/unit/lib/util.test.js new file mode 100644 index 00000000..3000fbab --- /dev/null +++ b/test/unit/lib/util.test.js @@ -0,0 +1,570 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files 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, the Mojaloop files are 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. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + + * Crosslake + - Lewis Daly + + -------------- + ******/ +'use strict' + +const Enum = require('@mojaloop/central-services-shared').Enum +jest.mock('axios') +const axios = require('axios') + +const { failActionHandler, getStackOrInspect, getSpanTags, generateRequestHeaders, generateRequestHeadersForJWS, removeEmptyKeys, fetchParticipantInfo } = require('../../../src/lib/util') + +describe('util', () => { + const mockData = { + amountTypeId: 'fakeAmountTypeId', + endpoints: { + payerfsp: 'http://localhost:8444/payerfsp', + payeefsp: 'http://localhost:8444/payeefsp', + invalid: 'http://invalid.com/', + invalidResponse: 'http://invalid-response.com/' + }, + geoCode: { + latitude: '42.69751', + longitude: '23.32415' + }, + headers: { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'fspiop-source': 'dfsp1', + 'fspiop-destination': 'dfsp2' + }, + switchHeaders: { + Accept: 'application/vnd.interoperability.transfers+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.transfers+json;version=1.0', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + initiatorType: 'fakeInitiatorType', + initiator: 'fakeInitiator', + quoteId: 'test123', + quoteRequest: { + quoteId: 'test123', + transactionId: 'abc123', + payee: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27824592509', + fspId: 'dfsp2' + } + }, + payer: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27713803905', + fspId: 'dfsp1' + } + }, + amountType: 'SEND', + amount: { + amount: 100, + currency: 'USD' + }, + transactionType: { + scenario: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER' + }, + geoCode: { + latitude: '43.69751', + longitude: '24.32415' + }, + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + quoteUpdate: { + transferAmount: { + amount: '100', + currency: 'USD' + }, + payeeReceiveAmount: { + amount: '95', + currency: 'USD' + }, + payeeFspFee: { + amount: '3', + currency: 'USD' + }, + payeeFspCommission: { + amount: '2', + currency: 'USD' + }, + expiration: '2019-10-30T10:30:19.899Z', + geoCode: { + latitude: '42.69751', + longitude: '23.32415' + }, + ilpPacket: '', + condition: 'HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks', + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + quoteResponse: { + quoteId: 'test123' + }, + rules: [ + { + conditions: { + all: [ + { + fact: 'json-path', + params: { + fact: 'payload', + path: '$.payload.extensionList[?(@.key == "KYCPayerTier")].value' + }, + operator: 'deepEqual', + value: ['1'] + }, + { + fact: 'payload', + path: '.amount.currency', + operator: 'notIn', + value: { + fact: 'json-path', + params: { + fact: 'payee', + path: '$.payee.accounts[?(@.ledgerAccountType == "SETTLEMENT")].currency' + } + } + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR' + } + } + }, + { + conditions: { + all: [ + { + fact: 'json-path', + params: { + fact: 'payload', + path: '$.payload.extensionList[?(@.key == "KYCPayerTier")].value' + }, + operator: 'notDeepEqual', + value: ['1'] + }, + { + fact: 'payload', + path: '.amount.currency', + operator: 'notIn', + value: { + fact: 'json-path', + params: { + fact: 'payee', + path: '$.payee.accounts[?(@.ledgerAccountType == "SETTLEMENT")].currency' + } + } + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_UNSUPPORTED_CURRENCY', + message: 'The requested payee does not support the payment currency' + } + } + } + ], + scenario: 'fakeScenario', + subScenario: 'fakeSubScenario', + transactionReference: 'fakeTxRef' + } + describe('failActionHandler', () => { + it('throws the reformatted error', async () => { + // Arrange + const input = new Error('Generic error') + + // Act + const action = async () => failActionHandler(null, null, input) + + // Assert + await expect(action()).rejects.toThrowError('Generic error') + }) + }) + + describe('getSpanTags', () => { + it('does not get the span tags for payeeFsp and payerFsp if they do not exist', () => { + // Arrange + const expected = { + transactionType: 'quote', + transactionAction: 'prepare', + transactionId: '12345', + quoteId: 'ABCDE', + source: 'fsp1', + destination: 'switch' + } + const mockRequest = { + params: { + id: 'ABCDE' + }, + payload: { + transactionId: '12345' + }, + headers: { + 'fspiop-source': 'fsp1', + 'fspiop-destination': 'switch' + } + } + + // Act + const result = getSpanTags(mockRequest, Enum.Events.Event.Type.QUOTE, Enum.Events.Event.Action.PREPARE) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('gets the span tags for payeeFsp and payerFsp if they do not exist', () => { + // Arrange + const expected = { + transactionType: 'quote', + transactionAction: 'prepare', + transactionId: '12345', + quoteId: 'ABCDE', + source: 'fsp1', + destination: 'switch', + payeeFsp: 'fsp1', + payerFsp: 'fsp2' + } + const mockRequest = { + params: { + id: 'ABCDE' + }, + payload: { + transactionId: '12345', + payee: { + partyIdInfo: { + fspId: 'fsp1' + } + }, + payer: { + partyIdInfo: { + fspId: 'fsp2' + } + } + }, + headers: { + 'fspiop-source': 'fsp1', + 'fspiop-destination': 'switch' + } + } + + // Act + const result = getSpanTags(mockRequest, Enum.Events.Event.Type.QUOTE, Enum.Events.Event.Action.PREPARE) + + // Assert + expect(result).toStrictEqual(expected) + }) + }) + + describe('getStackOrInspect', () => { + it('handles an error without a stack', () => { + // Arrange + const input = new Error('This is a normal error') + delete input.stack + const expected = '[Error: This is a normal error]' + + // Act + const output = getStackOrInspect(input) + + // Assert + expect(output).toBe(expected) + }) + }) + + describe('removeEmptyKeys', () => { + it('removes nothing if there are no empty keys', () => { + // Arrange + const input = { + a: 1, + b: 2, + c: 3 + } + const expected = { + a: 1, + b: 2, + c: 3 + } + + // Act + const result = removeEmptyKeys(input) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('removes a key and if it is undefined', () => { + // Arrange + const input = { + a: 1, + b: 2, + c: undefined + } + const expected = { + a: 1, + b: 2 + } + + // Act + const result = removeEmptyKeys(input) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('removes an empty key', () => { + // Arrange + const input = { + a: 1, + b: 2, + c: { + + } + } + const expected = { + a: 1, + b: 2 + } + + // Act + const result = removeEmptyKeys(input) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('removes a nested empty key', () => { + // Arrange + const input = { + a: 1, + b: 2, + c: { + d: { + + } + } + } + const expected = { + a: 1, + b: 2, + c: {} + } + + // Act + const result = removeEmptyKeys(input) + + // Assert + expect(result).toStrictEqual(expected) + }) + }) + + describe('generateRequestHeaders', () => { + it('generates the default request headers', () => { + // Arrange + const expected = { + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'FSPIOP-Destination': 'dfsp2', + 'FSPIOP-Source': 'dfsp1' + } + + // Act + const result = generateRequestHeaders(mockData.headers, true) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('generates default request headers, including the Accept', () => { + // Arrange + const expected = { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'FSPIOP-Destination': 'dfsp2', + 'FSPIOP-Source': 'dfsp1' + } + + // Act + const result = generateRequestHeaders(mockData.headers, false) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('generates default request headers, including the Accept and additionalHeaders', () => { + // Arrange + const expected = { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'FSPIOP-Destination': 'dfsp2', + 'FSPIOP-Source': 'dfsp1' + } + const additionalHeaders = { + 'x-fspsiop-sourcecurrency': 'EUR', + 'x-fspsiop-destinationcurrency': 'MAD' + } + + // Act + const result = generateRequestHeaders(mockData.headers, false, additionalHeaders) + + // Assert + expect(result).toStrictEqual({ ...expected, ...additionalHeaders }) + }) + + it('generates request headers, including the and converts accept and content-type to quotes', () => { + // Arrange + const expected = { + Accept: 'application/vnd.interoperability.quotes+json;version=1', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'FSPIOP-Destination': 'dfsp2', + 'FSPIOP-Source': 'switch' + } + + // Act + const result = generateRequestHeaders(mockData.switchHeaders, false) + + // Assert + expect(result).toStrictEqual(expected) + }) + }) + + describe('generateRequestHeadersForJWS', () => { + it('generates the default request headers', () => { + // Arrange + const expected = { + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'fspiop-destination': 'dfsp2', + 'fspiop-source': 'dfsp1' + } + + // Act + const result = generateRequestHeadersForJWS(mockData.headers, true) + + // Assert + expect(result).toStrictEqual(expected) + }) + + it('generates default request headers, including the Accept', () => { + // Arrange + const expected = { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'fspiop-destination': 'dfsp2', + 'fspiop-source': 'dfsp1' + } + + // Act + const result = generateRequestHeadersForJWS(mockData.headers, false) + + // Assert + expect(result).toStrictEqual(expected) + }) + }) + describe('fetchParticipantInfo', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + axios.request.mockRestore() + }) + + it('returns payer and payee', async () => { + // Arrange + const payer = { data: { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }] } } + const payee = { data: { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }] } } + axios.request + .mockImplementationOnce(() => { return payer }) + .mockImplementationOnce(() => { return payee }) + // Act + const result = await fetchParticipantInfo(mockData.headers['fspiop-source'], mockData.headers['fspiop-destination']) + // Assert + expect(result).toEqual({ payer: payer.data, payee: payee.data }) + expect(axios.request.mock.calls.length).toBe(2) + expect(axios.request.mock.calls[0][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-source'] }) + expect(axios.request.mock.calls[1][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-destination'] }) + }) + + it('throws an unhandled exception if the first attempt of `axios.request` throws an exception', async () => { + axios.request + .mockImplementationOnce(() => { throw new Error('foo') }) + + await expect(fetchParticipantInfo(mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'])) + .rejects + .toHaveProperty('message', 'foo') + + expect(axios.request.mock.calls.length).toBe(1) + expect(axios.request.mock.calls[0][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-source'] }) + }) + + it('throws an unhandled exception if the second attempt of `axios.request` throws an exception', async () => { + axios.request + .mockImplementationOnce(() => { return { success: true } }) + .mockImplementationOnce(() => { throw new Error('foo') }) + + await expect(fetchParticipantInfo(mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'])) + .rejects + .toHaveProperty('message', 'foo') + + expect(axios.request.mock.calls.length).toBe(2) + expect(axios.request.mock.calls[0][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-source'] }) + expect(axios.request.mock.calls[1][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-destination'] }) + }) + + it('throws an unhandled exception if the first attempt of `axios.request` fails', async () => { + axios.request + .mockImplementationOnce(() => { return Promise.reject(new Error('foo')) }) + .mockImplementationOnce(() => { return Promise.resolve({ ok: true }) }) + + await expect(fetchParticipantInfo(mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'])) + .rejects + .toHaveProperty('message', 'foo') + + expect(axios.request.mock.calls[0][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-source'] }) + expect(axios.request.mock.calls[1][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-destination'] }) + }) + + it('throws an unhandled exception if the second attempt of `axios.request` fails', async () => { + axios.request + .mockImplementationOnce(() => { return Promise.resolve({ ok: true }) }) + .mockImplementationOnce(() => { return Promise.reject(new Error('foo')) }) + + await expect(fetchParticipantInfo(mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'])) + .rejects + .toHaveProperty('message', 'foo') + + expect(axios.request.mock.calls.length).toBe(2) + expect(axios.request.mock.calls[0][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-source'] }) + expect(axios.request.mock.calls[1][0]).toEqual({ url: 'http://localhost:3001/participants/' + mockData.headers['fspiop-destination'] }) + }) + }) +}) diff --git a/test/unit/model/bulkQuotes.test.js b/test/unit/model/bulkQuotes.test.js new file mode 100644 index 00000000..f3f78095 --- /dev/null +++ b/test/unit/model/bulkQuotes.test.js @@ -0,0 +1,1022 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Rajiv Mothilal + -------------- + ******/ +'use strict' + +// jest has a buggy system for mocking dependencies that can be overcome by mocking +// the target module before requiring it. +// more info on https://github.com/facebook/jest/issues/2582#issuecomment-321607875 +let mockConfig + +jest.mock('axios') +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../src/data/database') +jest.mock('../../../src/lib/config', () => { + return jest.fn().mockImplementation(() => mockConfig) +}) +jest.mock('../../../src/lib/util') +jest.mock('../../../src/lib/http') + +const axios = require('axios') + +const Enum = require('@mojaloop/central-services-shared').Enum +const LibUtil = require('@mojaloop/central-services-shared').Util +const ErrorHandler = require('@mojaloop/central-services-error-handling') +const EventSdk = require('@mojaloop/event-sdk') +const Logger = require('@mojaloop/central-services-logger') +const JwsSigner = require('@mojaloop/sdk-standard-components').Jws.signer + +const Db = require('../../../src/data/database') +const Config = jest.requireActual('../../../src/lib/config') +const BulkQuotesModel = require('../../../src/model/bulkQuotes') +const Http = require('../../../src/lib/http') +const Util = require('../../../src/lib/util') + +const jwsSigningKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0eJEh3Op5p6x137lRkAsvmEBbd32dbRChrCUItZbtxjf/qfB +yD5k8Hn4n4vbqzP8XSGS0f6KmNC+iRaP74HVgzAqc4Uid4J8dtSBq3VmucYQYzLc +101QjuvD+SKmZwlw/q0PtulmqlASI2SbMfwcAraMi6ab7v5W4EGNeIPLEIo3BXsQ +DTCWqiZb7aXkHkcY7sOjAzK/2bNGYFmAthdYrHzvCkqnJ7LAHX3Oj7rJea5MqtuN +B9POZYaD10n9JuYWdwPqLrw6/hVgPSFEy+ulrVbXf54ZH0dfMThAYRvFrT81yulk +H95JhXWGdi6cTp6t8LVOKFhnNfxjWw0Jayj9xwIDAQABAoIBADB2u/Y/CgNbr5sg +DRccqHhJdAgHkep59kadrYch0knEL6zg1clERxCUSYmlxNKSjXp/zyQ4T46b3PNQ +x2m5pDDHxXWpT10jP1Q9G7gYwuCw0IXnb8EzdB+cZ0M28g+myXW1RoSo/nDjTlzn +1UJEgb9Kocd5cFZOWocr+9vRKumlZULMsA8yiNwlAfJHcMBM7acsa3myCqVhLyWt +4BQylVuLFa+A6QzpMXEwFCq8EOXf07gl1XVzC6LJ1fTa9gVM3N+YE+oEXKrsHCxG +/ACgKsjepL27QjJ7qvecWPP0F2LxEZYOm5tbXaKJTobzQUJHgUokanZMhjYprDsZ +zumLw9kCgYEA/DUWcnLeImlfq/EYdhejkl3J+WX3vhS23OqVgY1amu7CZzaai6vt +H0TRc8Zsbi4jgmFDU8PFzytP6qz6Tgom4R736z6oBi7bjnGyN17/NSbf+DaRVcM6 +vnZr7jNC2FJlECmIN+dkwUA/YCr2SA7hxZXM9mIYSc+6+glDiIO5Cf0CgYEA1Qo/ +uQbVHhW+Cp8H0kdMuhwUbkBquRrxRZlXS1Vrf3f9me9JLUy9UPWb3y3sKVurG5+O +SIlr4hDcZyXdE198MtDMhBIGqU9ORSjppJDNDVvtt+n2FD4XmWIU70vKBJBivX0+ +Bow6yduis+p12fuvpvpnKCz8UjOgOQJhLZ4GQBMCgYBP6gpozVjxkm4ML2LO2IKt ++CXtbo/nnOysZ3BkEoQpH4pd5gFmTF3gUJAFnVPyPZBm2abZvejJ0jGKbLELVVAo +eQWZdssK2oIbSo9r2CAJmX3SSogWorvUafWdDoUZwlHfoylUfW+BhHgQYsyS3JRR +ZTwCveZwTPA0FgdeFE7niQKBgQCHaD8+ZFhbCejDqXb4MXdUJ3rY5Lqwsq491YwF +huKPn32iNNQnJcqCxclv3iln1Cr6oLx34Fig1KSyLv/IS32OcuY635Y6UPznumxe +u+aJIjADIILXNOwdAplZy6s4oWkRFaSx1rmbCa3tew2zImTv1eJxR76MpOGmupt3 +uiQw3wKBgFjBT/aVKdBeHeP1rIHHldQV5QQxZNkc6D3qn/oAFcwpj9vcGfRjQWjO +ARzXM2vUWEet4OVn3DXyOdaWFR1ppehz7rAWBiPgsMg4fjAusYb9Mft1GMxMzuwT +Oyqsp6pzAWFrCD3JAoTLxClV+j5m+SXZ/ItD6ziGpl/h7DyayrFZ +-----END RSA PRIVATE KEY-----` + +describe('BulkQuotesModel', () => { + let mockData + let mockTransaction + let mockChildSpan + let mockSpan + let bulkQuotesModel + + mockConfig = new Config() + + beforeEach(() => { + axios.request.mockImplementation((opts) => { + if (opts.url.search('http://invalid.com') === 0) { + return Promise.reject(new Error('Unable to reach host')) + } else if (opts.url.search('http://invalid-response.com') === 0) { + return Promise.resolve({ status: 400 }) + } + if (opts.method === 'POST') { + return Promise.resolve({ status: 202 }) + } else { + return Promise.resolve({ status: 200 }) + } + }) + mockTransaction = { + commit: jest.fn(), + rollback: jest.fn() + } + mockChildSpan = { + injectContextToHttpRequest: jest.fn(opts => opts), + audit: jest.fn(), + isFinished: undefined, + finish: jest.fn() + } + mockSpan = { + getChild: jest.fn(() => mockChildSpan), + error: jest.fn(), + finish: jest.fn() + } + mockData = { + amountTypeId: 'fakeAmountTypeId', + endpoints: { + payerfsp: 'http://localhost:8444/payerfsp', + payeefsp: 'http://localhost:8444/payeefsp', + invalid: 'http://invalid.com/', + invalidResponse: 'http://invalid-response.com/' + }, + geoCode: { + latitude: '42.69751', + longitude: '23.32415' + }, + headers: { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'fspiop-source': 'dfsp1', + 'fspiop-destination': 'dfsp2' + }, + initiatorType: 'fakeInitiatorType', + initiator: 'fakeInitiator', + bulkQuoteId: 'test123', + bulkQuotePostRequest: { + bulkQuoteId: 'test123', + payer: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27713803905', + fspId: 'dfsp1' + } + }, + individualQuotes: [ + { + quoteId: 'test123', + transactionId: 'abc123', + payee: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27824592509', + fspId: 'dfsp2' + } + }, + amountType: 'SEND', + amount: { + amount: 100, + currency: 'USD' + }, + transactionType: { + scenario: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER' + }, + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + } + ], + geoCode: { + latitude: '43.69751', + longitude: '24.32415' + }, + expiration: '2019-10-30T10:30:19.899Z', + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + bulkQuoteUpdate: { + individualQuotesResults: [{ + bulkQuoteId: 'test123', + payee: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27713803905', + fspId: 'dfsp2' + } + }, + transferAmount: { + amount: '100', + currency: 'USD' + }, + payeeReceiveAmount: { + amount: '95', + currency: 'USD' + }, + payeeFspFee: { + amount: '3', + currency: 'USD' + }, + payeeFspCommission: { + amount: '2', + currency: 'USD' + }, + expiration: '2019-10-30T10:30:19.899Z', + ilpPacket: '', + condition: 'HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks', + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }], + expiration: '2019-10-30T10:30:19.899Z', + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + bulkQuoteResponse: { + bulkQuoteId: 'test123' + }, + scenario: 'fakeScenario', + subScenario: 'fakeSubScenario', + transactionReference: 'fakeTxRef' + } + + bulkQuotesModel = new BulkQuotesModel({ + db: new Db(), + requestId: mockData.bulkQuotePostRequest.bulkQuoteId + }) + bulkQuotesModel.db.newTransaction.mockImplementation(() => mockTransaction) + + bulkQuotesModel.db.createTransactionReference.mockImplementation(() => mockData.transactionReference) + bulkQuotesModel.db.getInitiatorType.mockImplementation(() => mockData.initiatorType) + bulkQuotesModel.db.getInitiator.mockImplementation(() => mockData.initiator) + bulkQuotesModel.db.getScenario.mockImplementation(() => mockData.scenario) + bulkQuotesModel.db.getSubScenario.mockImplementation(() => mockData.subScenario) + bulkQuotesModel.db.getAmountType.mockImplementation(() => mockData.amountTypeId) + bulkQuotesModel.db.createQuote.mockImplementation(() => mockData.bulkQuotePostRequest.quoteId) + bulkQuotesModel.db.createQuoteError.mockImplementation(() => mockData.bulkQuotePostRequest.quoteId) + bulkQuotesModel.db.createPayerQuoteParty.mockImplementation(() => mockData.bulkQuotePostRequest.payer.partyIdInfo.fspId) + bulkQuotesModel.db.createPayeeQuoteParty.mockImplementation(() => mockData.bulkQuotePostRequest.payee.partyIdInfo.fspId) + bulkQuotesModel.db.createGeoCode.mockImplementation(() => mockData.geoCode) + bulkQuotesModel.db.createQuoteExtensions.mockImplementation(() => mockData.bulkQuotePostRequest.extensionList.extension) + + // make all methods of the quotesModel instance be a mock. This helps us re-mock in every + // method's test suite. + const propertyNames = Object.getOwnPropertyNames(BulkQuotesModel.prototype) + propertyNames.forEach((methodName) => { + jest.spyOn(bulkQuotesModel, methodName).mockImplementation(() => { + return {} + }) + }) + }) + afterEach(() => { + // Clears the mock.calls and mock.instances properties of all mocks. + // Equivalent to calling .mockClear() on every mocked function. + jest.clearAllMocks() + + // reset the configuration values to their initials + mockConfig = new Config() + }) + + describe('validateBulkQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.validateBulkQuoteRequest.mockRestore() + }) + + it('should validate fspiopSource and fspiopDestination', async () => { + expect.assertions(5) + + const fspiopSource = 'dfsp1' + const fspiopDestination = 'dfsp2' + + expect(bulkQuotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() + + await bulkQuotesModel.validateBulkQuoteRequest(fspiopSource, fspiopDestination, mockData.bulkQuotePostRequest) + + expect(bulkQuotesModel.db).toBeTruthy() // Constructor should have been called + expect(bulkQuotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + expect(bulkQuotesModel.db.getParticipant.mock.calls[0][0]).toBe(fspiopSource) + expect(bulkQuotesModel.db.getParticipant.mock.calls[1][0]).toBe(fspiopDestination) + }) + }) + + describe('handleBulkQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.handleBulkQuoteRequest.mockRestore() + }) + + describe('Failures:', () => { + describe('Before forwarding the request:', () => { + it('throws an exception if `validateQuoteRequest` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + bulkQuotesModel.validateBulkQuoteRequest = jest.fn(() => { throw fspiopError }) + + await bulkQuotesModel.handleBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest, mockSpan) + expect(bulkQuotesModel.handleException).toHaveBeenCalledTimes(1) + }) + it('throws an exception if `span.getChild` fails', async () => { + expect.assertions(2) + + const spanError = new Error('foo') + mockSpan.getChild = jest.fn(() => { throw spanError }) + mockSpan.isFinished = false + await bulkQuotesModel.handleBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest, mockSpan) + expect(bulkQuotesModel.handleException).toHaveBeenCalledTimes(1) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + }) + }) + describe('While forwarding the request:', () => { + describe('In case environment is configured for simple routing mode', () => { + beforeEach(() => { + mockConfig.simpleRoutingMode = true + }) + + it('calls `handleException` with the proper arguments if `span.audit` fails', async () => { + expect.assertions(4) + + const spanError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(spanError) + mockChildSpan.audit = jest.fn(() => { throw spanError }) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], mockData.bulkQuoteId, fspiopError, mockData.headers, + mockChildSpan] + + const result = await bulkQuotesModel.handleBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest, mockSpan) + + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(bulkQuotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(bulkQuotesModel.handleException.mock.calls.length).toBe(1) + expect(result).toEqual({}) + }) + + it('calls `handleException` with the proper arguments if `forwardBulkQuoteRequest` fails', async () => { + expect.assertions(6) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + bulkQuotesModel.forwardBulkQuoteRequest = jest.fn(() => { throw fspiopError }) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], mockData.bulkQuoteId, fspiopError, mockData.headers, + mockChildSpan] + const expectedForwardQuoteRequestArgs = [mockData.headers, mockData.bulkQuotePostRequest.bulkQuoteId, mockData.bulkQuotePostRequest, mockChildSpan] + + const result = await bulkQuotesModel.handleBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest, mockSpan) + + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(bulkQuotesModel.forwardBulkQuoteRequest.mock.calls.length).toBe(1) + expect(bulkQuotesModel.forwardBulkQuoteRequest).toBeCalledWith(...expectedForwardQuoteRequestArgs) + expect(bulkQuotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(bulkQuotesModel.handleException.mock.calls.length).toBe(1) + expect(result).toEqual({}) + }) + }) + }) + }) + describe('Success:', () => { + describe('While forwarding the request:', () => { + describe('In case environment is configured for simple routing mode', () => { + it('forwards the bulk quote request properly', async () => { + expect.assertions(5) + + mockChildSpan.isFinished = false + + const result = await bulkQuotesModel.handleBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest, mockSpan) + + const expectedValidateQuoteRequestArgs = [mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'], mockData.bulkQuotePostRequest] + expect(bulkQuotesModel.validateBulkQuoteRequest).toBeCalledWith(...expectedValidateQuoteRequestArgs) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + + const expectedAuditArgs = [{ headers: mockData.headers, payload: mockData.bulkQuotePostRequest }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...expectedAuditArgs) + + const expectedForwardRequestArgs = [mockData.headers, mockData.bulkQuotePostRequest.bulkQuoteId, mockData.bulkQuotePostRequest, mockChildSpan] + expect(bulkQuotesModel.forwardBulkQuoteRequest).toBeCalledWith(...expectedForwardRequestArgs) + expect(result).toEqual({}) + }) + }) + }) + }) + }) + + describe('forwardBulkQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.forwardBulkQuoteRequest.mockRestore() + }) + + it('should get http status code 202 Accepted in simple routing mode', async () => { + expect.assertions(2) + mockConfig.simpleRoutingMode = true + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + + await bulkQuotesModel.forwardBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest.bulkQuoteId, mockData.bulkQuotePostRequest, mockChildSpan) + + expect(bulkQuotesModel.db.getParticipantEndpoint).toBeCalled() + expect(bulkQuotesModel.db.getQuotePartyEndpoint).not.toBeCalled() + }) + it('should throw when participant endpoint is not found', async () => { + expect.assertions(1) + + mockConfig.simpleRoutingMode = false + + bulkQuotesModel.db.getQuotePartyEndpoint.mockReturnValueOnce(undefined) + + await expect(bulkQuotesModel.forwardBulkQuoteRequest(mockData.headers, mockData.bulkQuotePostRequest.bulkQuoteId, mockData.bulkQuotePostRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) + }) + }) + + describe('handleBulkQuoteUpdate', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.handleBulkQuoteUpdate.mockRestore() + }) + + it('should forward quote update in simple routing mode', async () => { + expect.assertions(3) + mockChildSpan.isFinished = false + await bulkQuotesModel.handleBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockSpan) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + let args = [{ headers: mockData.headers, params: { bulkQuoteId: mockData.bulkQuotePostRequest.bulkQuoteId }, payload: mockData.bulkQuoteUpdate }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...args) + args = [mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockChildSpan] + expect(bulkQuotesModel.forwardBulkQuoteUpdate).toBeCalledWith(...args) + }) + it('should handle exception', async () => { + expect.assertions(5) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) + bulkQuotesModel.forwardBulkQuoteUpdate = jest.fn(() => { throw fspiopError }) + mockChildSpan.isFinished = false + await bulkQuotesModel.handleBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockSpan) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + let args = [{ headers: mockData.headers, params: { bulkQuoteId: mockData.bulkQuotePostRequest.bulkQuoteId }, payload: mockData.bulkQuoteUpdate }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...args) + args = [mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockChildSpan] + expect(bulkQuotesModel.forwardBulkQuoteUpdate).toBeCalledWith(...args) + args = [mockData.headers['fspiop-source'], mockData.bulkQuoteId, fspiopError, mockData.headers, mockChildSpan] + expect(bulkQuotesModel.handleException).toBeCalledWith(...args) + expect(bulkQuotesModel.handleException.mock.calls.length).toBe(1) + }) + it('should throw validationError when headers contains accept', async () => { + expect.assertions(3) + + const localHeaders = LibUtil.clone(mockData.headers) + localHeaders.accept = 'application/vnd.interoperability.quotes+json;version=1.0' + + await expect(bulkQuotesModel.handleBulkQuoteUpdate(localHeaders, mockData.bulkQuoteId, mockData.bulkQuoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR.code) + + expect(bulkQuotesModel.db.newTransaction.mock.calls.length).toBe(0) + expect(mockTransaction.rollback.mock.calls.length).toBe(0) + }) + }) + + describe('forwardQuoteUpdate', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.forwardBulkQuoteUpdate.mockRestore() + }) + + it('should get http status code 200 OK in simple routing mode', async () => { + expect.assertions(2) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + + await expect(bulkQuotesModel.forwardBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockChildSpan)) + .resolves + .toBe(undefined) + + expect(bulkQuotesModel.db.getParticipantEndpoint).toBeCalled() + }) + it('should throw when participant endpoint is not found', async () => { + expect.assertions(1) + + const endpoint = undefined + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(endpoint) + bulkQuotesModel.sendErrorCallback = jest.fn((_, fspiopError) => { throw fspiopError }) + + await expect(bulkQuotesModel.forwardBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate, mockChildSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) + }) + it('should not use spans when undefined and should throw when participant endpoint is invalid', async () => { + expect.assertions(3) + + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalid) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(bulkQuotesModel.forwardBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() + }) + it('should throw when participant endpoint returns invalid response', async () => { + expect.assertions(3) + + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalidResponse) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(bulkQuotesModel.forwardBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() + }) + it('should inspect and throw custom error as FSPIOPerror', async () => { + expect.assertions(3) + + const customErrorNoStack = new Error('Custom error') + delete customErrorNoStack.stack + bulkQuotesModel.db.getParticipantEndpoint.mockRejectedValueOnce(customErrorNoStack) + + await expect(bulkQuotesModel.forwardBulkQuoteUpdate(mockData.headers, mockData.bulkQuoteId, mockData.bulkQuoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() + }) + }) + + describe('handleBulkQuoteGet', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.handleBulkQuoteGet.mockRestore() + }) + + it('handles the bulk quote get with a child span', async () => { + // Arrange + expect.assertions(3) + + // Act + await bulkQuotesModel.handleBulkQuoteGet(mockData.headers, mockData.bulkQuoteId, mockSpan) + + // Assert + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(mockChildSpan.finish.mock.calls.length).toBe(1) + expect(bulkQuotesModel.forwardBulkQuoteGet.mock.calls.length).toBe(1) + }) + + it('handles an exception on `span.getChild`', async () => { + // Arrange + expect.assertions(1) + mockSpan.getChild = jest.fn(() => { throw new Error('Test Error') }) + + // Act + const action = async () => bulkQuotesModel.handleBulkQuoteGet(mockData.headers, mockData.bulkQuoteId, mockSpan) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + + it('handles an exception on `childSpan.audit`', async () => { + // Arrange + expect.assertions(2) + mockChildSpan.audit = jest.fn(() => { throw new Error('Test Error') }) + + // Act + await bulkQuotesModel.handleBulkQuoteGet(mockData.headers, mockData.bulkQuoteId, mockSpan) + + // Assert + expect(mockChildSpan.finish.mock.calls.length).toBe(1) + expect(bulkQuotesModel.handleException.mock.calls.length).toBe(1) + }) + }) + + describe('forwardQuoteGet', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.forwardBulkQuoteGet.mockRestore() + }) + + it('fails to forward if the database has no endpoint for the dfsp', async () => { + // Arrange + expect.assertions(1) + bulkQuotesModel.db.getParticipantEndpoint.mockImplementation(() => null) + + // Act + const action = async () => bulkQuotesModel.forwardBulkQuoteGet(mockData.headers, mockData.bulkQuoteId, mockSpan) + + // Assert + await expect(action()).rejects.toThrowError('No FSPIOP_CALLBACK_URL_BULK_QUOTES found for bulk quote GET test123') + }) + + it('forwards the request to the payee dfsp without a span', async () => { + // Arrange + // expect.assertions(2) + bulkQuotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + const expectedOptions = { + headers: {}, + method: 'GET', + url: 'http://localhost:3333/bulkQuotes/test123' + } + Util.generateRequestHeaders.mockImplementationOnce(() => { + return {} + }) + // Act + await bulkQuotesModel.forwardBulkQuoteGet(mockData.headers, mockData.bulkQuoteId) + + // Assert + expect(Http.httpRequest).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledWith(expectedOptions, mockData.headers[Enum.Http.Headers.FSPIOP.SOURCE]) + }) + + it('forwards the request to the payee dfsp', async () => { + // Arrange + expect.assertions(4) + bulkQuotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345' + } + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + headers: { + spanHeaders: '12345' + } + } + + // Act + await bulkQuotesModel.forwardBulkQuoteGet(mockData.headers, mockData.bulkQuoteId, mockSpan) + + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledWith(expectedOptions, mockData.headers[Enum.Http.Headers.FSPIOP.SOURCE]) + }) + + it('handles a http error', async () => { + // Arrange + expect.assertions(1) + bulkQuotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + Http.httpRequest.mockImplementationOnce(() => { throw new Error('Test HTTP Error') }) + + // Act + const action = async () => bulkQuotesModel.forwardBulkQuoteGet(mockData.headers, mockData.bulkQuoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test HTTP Error') + }) + }) + + describe('handleBulkQuoteError', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.handleBulkQuoteError.mockRestore() + }) + + it('handles the quote error', async () => { + // Arrange + expect.assertions(2) + const error = { + errorCode: 2001, + errorDescription: 'Test Error' + } + + // Act + const result = await bulkQuotesModel.handleBulkQuoteError(mockData.headers, mockData.bulkQuoteId, error, mockSpan) + + // Assert + // For `handleQuoteError` response is undefined + expect(result).toBe(undefined) + expect(bulkQuotesModel.sendErrorCallback).toHaveBeenCalledTimes(1) + }) + + it('sends the error callback to the correct destination', async () => { + // Arrange + expect.assertions(3) + const error = { + errorCode: 2001, + errorDescription: 'Test Error' + } + bulkQuotesModel.sendErrorCallback = jest.fn() + + // Act + const result = await bulkQuotesModel.handleBulkQuoteError(mockData.headers, mockData.bulkQuoteId, error, mockSpan) + + // Assert + // For `handleQuoteError` response is undefined + expect(result).toBe(undefined) + expect(bulkQuotesModel.sendErrorCallback).toHaveBeenCalledTimes(1) + expect(bulkQuotesModel.sendErrorCallback.mock.calls[0][0]) + .toEqual(mockData.headers[Enum.Http.Headers.FSPIOP.DESTINATION]) + }) + + it('handles bad error input', async () => { + // Arrange + expect.assertions(1) + const error = { + errorDescription: 'Test Error' + } + + // Act + const action = async () => bulkQuotesModel.handleBulkQuoteError(mockData.headers, mockData.bulkQuoteId, error, mockSpan) + await action() + // const es = 'Factory function createFSPIOPError failed due to apiErrorCode being invalid' + // Assert + expect(bulkQuotesModel.handleException).toHaveBeenCalledTimes(1) + }) + }) + + describe('handleException', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.handleException.mockRestore() + }) + + it('handles the error and finishes the child span', async () => { + // Arrange + expect.assertions(3) + const error = new Error('Test Error') + const expectedError = ErrorHandler.ReformatFSPIOPError(error) + bulkQuotesModel.sendErrorCallback.mockImplementationOnce(() => true) + + // Act + const result = await bulkQuotesModel.handleException('payeefsp', mockData.bulkQuoteId, error, mockData.headers, mockSpan) + + // Assert + expect(bulkQuotesModel.sendErrorCallback).toHaveBeenCalledWith('payeefsp', expectedError, mockData.bulkQuoteId, mockData.headers, mockChildSpan, true) + expect(result).toBe(true) + expect(mockChildSpan.finish).toHaveBeenCalledTimes(1) + }) + + it('handles an error in sendErrorCallback', async () => { + // Arrange + expect.assertions(3) + const error = new Error('Test Error') + const expectedError = ErrorHandler.ReformatFSPIOPError(error) + bulkQuotesModel.sendErrorCallback.mockImplementationOnce(() => { throw new Error('Error sending callback.') }) + + // Act + await bulkQuotesModel.handleException('payeefsp', mockData.bulkQuoteId, error, mockData.headers, mockSpan) + + // Assert + expect(bulkQuotesModel.sendErrorCallback).toHaveBeenCalledWith('payeefsp', expectedError, mockData.bulkQuoteId, mockData.headers, mockChildSpan, true) + expect(bulkQuotesModel.writeLog).toHaveBeenCalledTimes(1) + expect(mockChildSpan.finish).toHaveBeenCalledTimes(1) + }) + }) + + describe('sendErrorCallback', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.sendErrorCallback.mockRestore() + }) + + it('sends the error callback without a span', async () => { + // Arrange + expect.assertions(1) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/bulkQuotes/test123/error', + data: JSON.stringify(fspiopError.toApiErrorObject(mockConfig.errorHandling), LibUtil.getCircularReplacer()), + headers: {} + } + + // Act + await bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers) + + // Assert + expect(axios.request).toBeCalledWith(expectedOptions) + }) + + it('sends the error callback and handles the span', async () => { + // Arrange + expect.assertions(3) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345' + } + } + + // Act + await bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers, mockSpan) + + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(axios.request).toBeCalledWith(expectedOptions) + }) + + it('sends the error callback JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + // expect.assertions(6) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + mockConfig.jws.jwsSign = true + mockConfig.jws.jwsSigningKey = jwsSigningKey + // Act + await bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers, mockSpan, true) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).toBeCalledTimes(1) + expect(axios.request.mock.calls[0][0].headers).toHaveProperty('fspiop-signature') + expect(axios.request.mock.calls[0][0].headers['fspiop-signature']).toEqual(expect.stringContaining('signature')) + expect(axios.request.mock.calls[0][0].headers['fspiop-signature']).toEqual(expect.stringContaining('protectedHeader')) + jwsSignSpy.mockRestore() + }) + + it('sends the error callback NOT JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + expect.assertions(5) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + } + } + mockConfig.jws.jwsSign = false + // Act + await bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers, mockSpan, true) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).not.toHaveBeenCalled() + expect(axios.request.mock.calls[0][0].headers).not.toHaveProperty('fspiop-signature') + expect(axios.request).toBeCalledWith(expectedOptions) + jwsSignSpy.mockRestore() + }) + + it('sends the error callback NOT JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + expect.assertions(5) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + } + } + mockConfig.jws.jwsSign = false + // Act + await bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers, mockSpan, false) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).not.toHaveBeenCalled() + expect(axios.request.mock.calls[0][0].headers).not.toHaveProperty('fspiop-signature') + expect(axios.request).toBeCalledWith(expectedOptions) + jwsSignSpy.mockRestore() + }) + + it('handles when the endpoint could not be found', async () => { + // Arrange + expect.assertions(2) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(undefined) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + + // Act + const action = async () => bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers, mockSpan) + + // Assert + await expect(action()).rejects.toThrow('No FSPIOP_CALLBACK_URL_BULK_QUOTES found for payeefsp unable to make error callback') + expect(axios.request).not.toHaveBeenCalled() + }) + + it('handles a http exception', async () => { + // Arrange + expect.assertions(2) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + axios.request.mockImplementationOnce(() => { throw new Error('HTTP test error') }) + + // Act + const action = async () => bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers) + + // Assert + await expect(action()).rejects.toThrow('network error in sendErrorCallback: HTTP test error') + expect(axios.request).toHaveBeenCalledTimes(1) + }) + + it('handles a http bad status code', async () => { + // Arrange + expect.assertions(2) + bulkQuotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + axios.request.mockReturnValueOnce({ + status: Enum.Http.ReturnCodes.BADREQUEST.CODE + }) + + // Act + const action = async () => bulkQuotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.bulkQuoteId, mockData.headers) + + // Assert + await expect(action()).rejects.toThrow('Got non-success response sending error callback') + expect(axios.request).toHaveBeenCalledTimes(1) + }) + }) + + describe('writeLog', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + bulkQuotesModel.writeLog.mockRestore() + }) + + it('writes to the log', () => { + // Arrange + // Act + bulkQuotesModel.writeLog('test message') + + // Assert + expect(Logger.info).toBeCalledTimes(1) + }) + }) +}) diff --git a/test/unit/model/quotes.test.js b/test/unit/model/quotes.test.js index ec1cac08..ae04eb8c 100644 --- a/test/unit/model/quotes.test.js +++ b/test/unit/model/quotes.test.js @@ -2,9 +2,9 @@ License -------------- Copyright © 2017 Bill & Melinda Gates Foundation - The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + Unless required by applicable law or agreed to in writing, the Mojaloop files are 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. Initial contribution -------------------- @@ -26,650 +26,1349 @@ * ModusBox - Georgi Georgiev + - Matt Kingston + - Vassilis Barzokas + - James Bush -------------- ******/ 'use strict' -const QuotesModel = require('../../../src/model/quotes') +// jest has a buggy system for mocking dependencies that can be overcome by mocking +// the target module before requiring it. +// more info on https://github.com/facebook/jest/issues/2582#issuecomment-321607875 +const mockRules = [{}] +let mockConfig + +jest.mock('../../../config/rules.json', () => mockRules) +jest.mock('axios') +jest.mock('@mojaloop/central-services-logger') +jest.mock('../../../src/data/database') +jest.mock('../../../src/model/rules') +jest.mock('../../../src/lib/config', () => { + return jest.fn().mockImplementation(() => mockConfig) +}) +jest.mock('../../../src/lib/util') +jest.mock('../../../src/lib/http') + +const axios = require('axios') + +const clone = require('@mojaloop/central-services-shared').Util.clone +const Enum = require('@mojaloop/central-services-shared').Enum +const LibUtil = require('@mojaloop/central-services-shared').Util const ErrorHandler = require('@mojaloop/central-services-error-handling') const EventSdk = require('@mojaloop/event-sdk') -const Config = require('../../../config/default') -const RulesEngine = require('../../../src/model/rules') -const clone = require('@mojaloop/central-services-shared').Util.clone -const mockAxios = require('axios') +const Logger = require('@mojaloop/central-services-logger') +const JwsSigner = require('@mojaloop/sdk-standard-components').Jws.signer const Db = require('../../../src/data/database') -const mockTransaction = { - commit: jest.fn(), - rollback: jest.fn() -} -const mockDb = { - getParticipant: jest.fn(), - newTransaction: jest.fn(() => mockTransaction), - getQuoteDuplicateCheck: jest.fn(), - createQuoteDuplicateCheck: jest.fn(), - createTransactionReference: jest.fn(), - getInitiatorType: jest.fn(), - getInitiator: jest.fn(), - getScenario: jest.fn(), - getAmountType: jest.fn(), - createQuote: jest.fn(), - createPayerQuoteParty: jest.fn(), - createPayeeQuoteParty: jest.fn(), - getSubScenario: jest.fn(), - createGeoCode: jest.fn(), - getParticipantEndpoint: jest.fn(), - getQuotePartyEndpoint: jest.fn(), - createQuoteResponse: jest.fn(), - createQuoteUpdateDuplicateCheck: jest.fn(), - createQuoteResponseIlpPacket: jest.fn(), - getQuoteParty: jest.fn() -} -jest.mock('../../../src/data/database', () => { - return jest.fn().mockImplementation(() => { - return { - getParticipant: mockDb.getParticipant, - newTransaction: mockDb.newTransaction, - getQuoteDuplicateCheck: mockDb.getQuoteDuplicateCheck, - createQuoteDuplicateCheck: mockDb.createQuoteDuplicateCheck, - createTransactionReference: mockDb.createTransactionReference, - getInitiatorType: mockDb.getInitiatorType, - getInitiator: mockDb.getInitiator, - getScenario: mockDb.getScenario, - getAmountType: mockDb.getAmountType, - createQuote: mockDb.createQuote, - createPayerQuoteParty: mockDb.createPayerQuoteParty, - createPayeeQuoteParty: mockDb.createPayeeQuoteParty, - getSubScenario: mockDb.getSubScenario, - createGeoCode: mockDb.createGeoCode, - getParticipantEndpoint: mockDb.getParticipantEndpoint, - getQuotePartyEndpoint: mockDb.getQuotePartyEndpoint, - createQuoteResponse: mockDb.createQuoteResponse, - createQuoteUpdateDuplicateCheck: mockDb.createQuoteUpdateDuplicateCheck, - createQuoteResponseIlpPacket: mockDb.createQuoteResponseIlpPacket, - getQuoteParty: mockDb.getQuoteParty - } - }) -}) - -const mockChildSpan = { - injectContextToHttpRequest: jest.fn(opts => opts), - audit: jest.fn(), - isFinished: undefined, - finish: jest.fn() -} -const mockSpan = { - getChild: jest.fn(() => mockChildSpan), - error: jest.fn(), - finish: jest.fn() -} - -const rules = require(`${__ROOT__}/config/rules.example.json`) - -jest.mock('../../../src/model/rules', () => { - return { - events: { - INTERCEPT_QUOTE: 'INTERCEPT_QUOTE', - INVALID_QUOTE_REQUEST: 'INVALID_QUOTE_REQUEST' - }, - run: jest.fn(() => { - return { - events: [] - } - }) - } -}) +const Config = jest.requireActual('../../../src/lib/config') +const QuotesModel = require('../../../src/model/quotes') +const rules = require('../../../config/rules') +const RulesEngine = require('../../../src/model/rules') +const Http = require('../../../src/lib/http') +const Util = require('../../../src/lib/util') + +const jwsSigningKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0eJEh3Op5p6x137lRkAsvmEBbd32dbRChrCUItZbtxjf/qfB +yD5k8Hn4n4vbqzP8XSGS0f6KmNC+iRaP74HVgzAqc4Uid4J8dtSBq3VmucYQYzLc +101QjuvD+SKmZwlw/q0PtulmqlASI2SbMfwcAraMi6ab7v5W4EGNeIPLEIo3BXsQ +DTCWqiZb7aXkHkcY7sOjAzK/2bNGYFmAthdYrHzvCkqnJ7LAHX3Oj7rJea5MqtuN +B9POZYaD10n9JuYWdwPqLrw6/hVgPSFEy+ulrVbXf54ZH0dfMThAYRvFrT81yulk +H95JhXWGdi6cTp6t8LVOKFhnNfxjWw0Jayj9xwIDAQABAoIBADB2u/Y/CgNbr5sg +DRccqHhJdAgHkep59kadrYch0knEL6zg1clERxCUSYmlxNKSjXp/zyQ4T46b3PNQ +x2m5pDDHxXWpT10jP1Q9G7gYwuCw0IXnb8EzdB+cZ0M28g+myXW1RoSo/nDjTlzn +1UJEgb9Kocd5cFZOWocr+9vRKumlZULMsA8yiNwlAfJHcMBM7acsa3myCqVhLyWt +4BQylVuLFa+A6QzpMXEwFCq8EOXf07gl1XVzC6LJ1fTa9gVM3N+YE+oEXKrsHCxG +/ACgKsjepL27QjJ7qvecWPP0F2LxEZYOm5tbXaKJTobzQUJHgUokanZMhjYprDsZ +zumLw9kCgYEA/DUWcnLeImlfq/EYdhejkl3J+WX3vhS23OqVgY1amu7CZzaai6vt +H0TRc8Zsbi4jgmFDU8PFzytP6qz6Tgom4R736z6oBi7bjnGyN17/NSbf+DaRVcM6 +vnZr7jNC2FJlECmIN+dkwUA/YCr2SA7hxZXM9mIYSc+6+glDiIO5Cf0CgYEA1Qo/ +uQbVHhW+Cp8H0kdMuhwUbkBquRrxRZlXS1Vrf3f9me9JLUy9UPWb3y3sKVurG5+O +SIlr4hDcZyXdE198MtDMhBIGqU9ORSjppJDNDVvtt+n2FD4XmWIU70vKBJBivX0+ +Bow6yduis+p12fuvpvpnKCz8UjOgOQJhLZ4GQBMCgYBP6gpozVjxkm4ML2LO2IKt ++CXtbo/nnOysZ3BkEoQpH4pd5gFmTF3gUJAFnVPyPZBm2abZvejJ0jGKbLELVVAo +eQWZdssK2oIbSo9r2CAJmX3SSogWorvUafWdDoUZwlHfoylUfW+BhHgQYsyS3JRR +ZTwCveZwTPA0FgdeFE7niQKBgQCHaD8+ZFhbCejDqXb4MXdUJ3rY5Lqwsq491YwF +huKPn32iNNQnJcqCxclv3iln1Cr6oLx34Fig1KSyLv/IS32OcuY635Y6UPznumxe +u+aJIjADIILXNOwdAplZy6s4oWkRFaSx1rmbCa3tew2zImTv1eJxR76MpOGmupt3 +uiQw3wKBgFjBT/aVKdBeHeP1rIHHldQV5QQxZNkc6D3qn/oAFcwpj9vcGfRjQWjO +ARzXM2vUWEet4OVn3DXyOdaWFR1ppehz7rAWBiPgsMg4fjAusYb9Mft1GMxMzuwT +Oyqsp6pzAWFrCD3JAoTLxClV+j5m+SXZ/ItD6ziGpl/h7DyayrFZ +-----END RSA PRIVATE KEY-----` + +describe('QuotesModel', () => { + let mockData + let mockTransaction + let mockChildSpan + let mockSpan + let quotesModel -jest.mock('@mojaloop/central-services-logger', () => { - return { - info: jest.fn() // suppress info output - } -}) + mockConfig = new Config() -jest.mock('axios') -mockAxios.request = (opts) => { - if (opts.url.search('http://invalid.com') === 0) { - return Promise.reject(new Error('Unable to reach host')) - } else if (opts.url.search('http://invalid-response.com') === 0) { - return Promise.resolve({ status: 400 }) - } - if (opts.method === 'POST') { - return Promise.resolve({ status: 202 }) - } else { - return Promise.resolve({ status: 200 }) - } -} - -jest.useFakeTimers() -const flushPromises = () => new Promise(setImmediate) - -describe('quotesModel', () => { - const headers = { - 'fspiop-source': 'dfsp1', - 'fspiop-destination': 'dfsp2' - } - const quoteId = 'test123' - const quoteRequest = { - quoteId, - transactionId: 'abc123', - payee: { - partyIdInfo: { - partyIdType: 'MSISDN', - partyIdentifier: '27824592509', - fspId: 'dfsp2' + beforeEach(() => { + axios.request.mockImplementation((opts) => { + if (opts.url.search('http://invalid.com') === 0) { + return Promise.reject(new Error('Unable to reach host')) + } else if (opts.url.search('http://invalid-response.com') === 0) { + return Promise.resolve({ status: 400 }) } - }, - payer: { - partyIdInfo: { - partyIdType: 'MSISDN', - partyIdentifier: '27713803905', - fspId: 'dfsp1' + if (opts.method === 'POST') { + return Promise.resolve({ status: 202 }) + } else { + return Promise.resolve({ status: 200 }) } - }, - amountType: 'SEND', - amount: { - amount: 100, - currency: 'USD' - }, - transactionType: { - scenario: 'TRANSFER', - initiator: 'PAYER', - initiatorType: 'CONSUMER' + }) + mockTransaction = { + commit: jest.fn(), + rollback: jest.fn() } - } - const quoteUpdate = { - transferAmount: { - amount: '100', - currency: 'USD' - }, - payeeReceiveAmount: { - amount: '95', - currency: 'USD' - }, - payeeFspFee: { - amount: '3', - currency: 'USD' - }, - payeeFspCommission: { - amount: '2', - currency: 'USD' - }, - expiration: '2019-10-30T10:30:19.899Z', - geoCode: { - latitude: '42.69751', - longitude: '23.32415' - }, - ilpPacket: '', - condition: 'HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks', - extensionList: { - extension: [{ - key: 'key1', - value: 'value1' - }] + mockChildSpan = { + injectContextToHttpRequest: jest.fn(opts => opts), + audit: jest.fn(), + isFinished: undefined, + finish: jest.fn(), + error: jest.fn(), + getChild: jest.fn(() => mockChildSpan) + } + mockSpan = { + getChild: jest.fn(() => mockChildSpan), + error: jest.fn(), + finish: jest.fn() + } + mockData = { + amountTypeId: 'fakeAmountTypeId', + endpoints: { + payerfsp: 'http://localhost:8444/payerfsp', + payeefsp: 'http://localhost:8444/payeefsp', + invalid: 'http://invalid.com/', + invalidResponse: 'http://invalid-response.com/' + }, + geoCode: { + latitude: '42.69751', + longitude: '23.32415' + }, + headers: { + Accept: 'application/vnd.interoperability.quotes+json;version=1.0', + 'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0', + 'fspiop-source': 'dfsp1', + 'fspiop-destination': 'dfsp2' + }, + initiatorType: 'fakeInitiatorType', + initiator: 'fakeInitiator', + quoteId: 'test123', + quoteRequest: { + quoteId: 'test123', + transactionId: 'abc123', + payee: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27824592509', + fspId: 'dfsp2' + } + }, + payer: { + partyIdInfo: { + partyIdType: 'MSISDN', + partyIdentifier: '27713803905', + fspId: 'dfsp1' + } + }, + amountType: 'SEND', + amount: { + amount: 100, + currency: 'USD' + }, + transactionType: { + scenario: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER' + }, + geoCode: { + latitude: '43.69751', + longitude: '24.32415' + }, + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + quoteUpdate: { + transferAmount: { + amount: '100', + currency: 'USD' + }, + payeeReceiveAmount: { + amount: '95', + currency: 'USD' + }, + payeeFspFee: { + amount: '3', + currency: 'USD' + }, + payeeFspCommission: { + amount: '2', + currency: 'USD' + }, + expiration: '2019-10-30T10:30:19.899Z', + geoCode: { + latitude: '42.69751', + longitude: '23.32415' + }, + ilpPacket: '', + condition: 'HOr22-H3AfTDHrSkPjJtVPRdKouuMkDXTR4ejlQa8Ks', + extensionList: { + extension: [{ + key: 'key1', + value: 'value1' + }] + } + }, + quoteResponse: { + quoteId: 'test123' + }, + rules: [ + { + conditions: { + all: [ + { + fact: 'json-path', + params: { + fact: 'payload', + path: '$.payload.extensionList[?(@.key == "KYCPayerTier")].value' + }, + operator: 'deepEqual', + value: ['1'] + }, + { + fact: 'payload', + path: '.amount.currency', + operator: 'notIn', + value: { + fact: 'json-path', + params: { + fact: 'payee', + path: '$.payee.accounts[?(@.ledgerAccountType == "POSITION" && @.isActive == 1)].currency' + } + } + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR', + sourceCurrency: 'EUR', + rerouteToFspCurrency: 'XOF', + additionalHeaders: { + 'x-fspiop-sourcecurrency': 'EUR', + 'x-fspiop-destinationcurrency': 'XOF' + } + } + } + }, + { + conditions: { + all: [ + { + fact: 'json-path', + params: { + fact: 'payload', + path: '$.payload.extensionList[?(@.key == "KYCPayerTier")].value' + }, + operator: 'notDeepEqual', + value: ['1'] + }, + { + fact: 'payload', + path: '.amount.currency', + operator: 'notIn', + value: { + fact: 'json-path', + params: { + fact: 'payee', + path: '$.payee.accounts[?(@.ledgerAccountType == "POSITION" && @.isActive == 1)].currency' + } + } + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_UNSUPPORTED_CURRENCY', + message: 'The requested payee does not support the payment currency' + } + } + } + ], + scenario: 'fakeScenario', + subScenario: 'fakeSubScenario', + transactionReference: 'fakeTxRef', + payer: { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 1 }, + payee: { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 1 } } - } - const endpoints = { - payerfsp: 'http://localhost:8444/payerfsp', - payeefsp: 'http://localhost:8444/payeefsp', - invalid: 'http://invalid.com/', - invalidResponse: 'http://invalid-response.com/' - } - let quotesModel - beforeAll(() => {}) - beforeEach(() => { quotesModel = new QuotesModel({ db: new Db(), - requestId: 'test1234' - }) - Db.mockClear() - mockTransaction.commit.mockClear() - mockTransaction.rollback.mockClear() - mockDb.getParticipant.mockClear() - mockDb.newTransaction.mockClear() - mockDb.getQuoteDuplicateCheck.mockClear() - mockDb.createQuoteDuplicateCheck.mockClear() - mockDb.createTransactionReference.mockClear() - mockDb.getInitiatorType.mockClear() - mockDb.getInitiator.mockClear() - mockDb.getScenario.mockClear() - mockDb.getAmountType.mockClear() - mockDb.createQuote.mockClear() - mockDb.createPayerQuoteParty.mockClear() - mockDb.createPayeeQuoteParty.mockClear() - mockDb.getSubScenario.mockClear() - mockDb.createGeoCode.mockClear() - mockDb.getParticipantEndpoint.mockClear() - mockDb.getQuotePartyEndpoint.mockClear() - mockChildSpan.injectContextToHttpRequest.mockClear() - mockChildSpan.audit.mockClear() - mockChildSpan.finish.mockClear() - mockSpan.getChild.mockClear() - mockSpan.error.mockClear() - mockSpan.finish.mockClear() - RulesEngine.run.mockClear() + requestId: mockData.quoteRequest.quoteId + }) + quotesModel.db.newTransaction.mockImplementation(() => mockTransaction) + + quotesModel.db.createTransactionReference.mockImplementation(() => mockData.transactionReference) + quotesModel.db.getInitiatorType.mockImplementation(() => mockData.initiatorType) + quotesModel.db.getInitiator.mockImplementation(() => mockData.initiator) + quotesModel.db.getScenario.mockImplementation(() => mockData.scenario) + quotesModel.db.getSubScenario.mockImplementation(() => mockData.subScenario) + quotesModel.db.getAmountType.mockImplementation(() => mockData.amountTypeId) + quotesModel.db.createQuote.mockImplementation(() => mockData.quoteRequest.quoteId) + quotesModel.db.createQuoteError.mockImplementation(() => mockData.quoteRequest.quoteId) + quotesModel.db.createPayerQuoteParty.mockImplementation(() => mockData.quoteRequest.payer.partyIdInfo.fspId) + quotesModel.db.createPayeeQuoteParty.mockImplementation(() => mockData.quoteRequest.payee.partyIdInfo.fspId) + quotesModel.db.createGeoCode.mockImplementation(() => mockData.geoCode) + quotesModel.db.createQuoteExtensions.mockImplementation(() => mockData.quoteRequest.extensionList.extension) + + // make all methods of the quotesModel instance be a mock. This helps us re-mock in every + // method's test suite. + const propertyNames = Object.getOwnPropertyNames(QuotesModel.prototype) + propertyNames.forEach((methodName) => { + jest.spyOn(quotesModel, methodName).mockImplementation(() => { + return {} + }) + }) + + // some unit tests rely on specific results from some methods so we explicitly define them below + jest.spyOn(quotesModel, 'handleRuleEvents').mockImplementation(jest.fn(() => { + return { + headers: mockData.headers, + quoteRequest: mockData.quoteRequest + } + })) + }) + afterEach(() => { + // Clears the mock.calls and mock.instances properties of all mocks. + // Equivalent to calling .mockClear() on every mocked function. + jest.clearAllMocks() + + // reset the configuration values to their initials + mockConfig = new Config() + + // reset the rules values to their initials, but without changing the object's reference + // as we use the same object between the current unit tests file and the code's implementation + Object.keys(mockData.rules).forEach(key => { + rules[key] = mockData.rules[key] + }) + }) + + describe('executeRules', () => { + beforeEach(() => { + quotesModel.executeRules.mockRestore() + }) + + describe('Failures:', () => { + describe('In case a non empty set of rules is loaded', () => { + it('throws an unhandled exception if `RulesEngine.run` throws an exception', async () => { + const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }] } + const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }] } + RulesEngine.run.mockImplementation(() => { throw new Error('foo') }) + + await expect(quotesModel.executeRules(mockData.headers, mockData.quoteRequest, payer, payee)) + .rejects + .toHaveProperty('message', 'foo') + }) + }) + }) + + describe('Success:', () => { + describe('In case an empty set of rules is loaded', () => { + beforeEach(() => { + // keep the reference to the original rules array, as it the same values are used by + // the current unit tests file and the code's implementation + rules.length = 0 + }) + + it('stops execution', async () => { + expect(rules.length).toBe(0) + + await expect(quotesModel.executeRules(mockData.headers, mockData.quoteRequest)) + .resolves + .toEqual([]) + + expect(axios.request.mock.calls.length).toBe(0) + }) + }) + describe('In case a non empty set of rules is loaded', () => { + it('returns the result of `RulesEngine.run`', async () => { + const expectedEvents = [] + rules.forEach((rule) => { + expectedEvents.push(rule.event) + }) + + RulesEngine.run.mockImplementation(() => { + return { + events: expectedEvents + } + }) + const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }] } + const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }] } + + await expect(quotesModel.executeRules(mockData.headers, mockData.quoteRequest, payer, payee)) + .resolves + .toEqual(expectedEvents) + }) + }) + }) }) - afterEach(() => {}) - afterAll(() => {}) + describe('handleRuleEvents', () => { + beforeEach(() => { + quotesModel.handleRuleEvents.mockRestore() + }) + describe('Failures:', () => { + describe('In case one event is passed', () => { + let mockEvents + + describe('In case it has type of `INVALID_QUOTE_REQUEST`', () => { + beforeEach(() => { + mockEvents = [mockData.rules[1].event] + }) + + it('throws an exception according to the error type specified inside the event\'s parameters', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes[mockData.rules[1].event.params.FSPIOPError].code) + }) + }) + describe('In case it has an unknown type', () => { + beforeEach(() => { + mockEvents = [mockData.rules[0].event] + mockEvents[0].type = 'something-that-is-not-known' + }) + + it('throws an exception with an appropriate error message', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('message', 'Unhandled event returned by rules engine') + }) + }) + }) + describe('In case multiple events are passed', () => { + let mockEvents + + describe('In case one of them has type of `INVALID_QUOTE_REQUEST`', () => { + beforeEach(() => { + mockEvents = [mockData.rules[0].event, mockData.rules[1].event] + }) + + it('throws an exception according to the error type specified inside the event\'s parameters', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes[mockData.rules[1].event.params.FSPIOPError].code) + }) + }) + describe('In case more than one have type of `INTERCEPT_QUOTE`', () => { + beforeEach(() => { + mockEvents = [mockData.rules[0].event, mockData.rules[0].event] + }) + + it('throws an exception with an appropriate error message', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('message', 'Multiple intercept quote events received') + }) + }) + describe('In case one of them has an unknown type and one of them has type of `INTERCEPT_QUOTE`', () => { + beforeEach(() => { + mockEvents = [ + clone(mockData.rules[0].event), + clone(mockData.rules[0].event) + ] + mockEvents[0].type = 'something-that-is-not-known' + }) + + it('throws an exception with an appropriate error message', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('message', 'Unhandled event returned by rules engine') + }) + }) + describe('In case all of them have an unknown type', () => { + beforeEach(() => { + mockEvents = [ + clone(mockData.rules[0].event), + clone(mockData.rules[0].event) + ] + mockEvents[0].type = 'something-that-is-not-known-1' + mockEvents[1].type = 'something-that-is-not-known-2' + }) + + it('throws an exception with an appropriate error message', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .rejects + .toHaveProperty('message', 'Unhandled event returned by rules engine') + }) + }) + }) + }) + describe('Success:', () => { + describe('In case no events are passed', () => { + it('terminates execution and passes back an appropriate result', async () => { + await expect(quotesModel.handleRuleEvents([], mockData.headers, mockData.quoteRequest)).resolves.toStrictEqual({ + terminate: false, + quoteRequest: mockData.quoteRequest, + headers: mockData.headers + }) + }) + }) + describe('In case one event is passed', () => { + let mockEvents + + describe('In case it has type of `INTERCEPT_QUOTE`', () => { + beforeEach(() => { + mockEvents = [mockData.rules[0].event] + }) + + it('returns an expected response object', async () => { + await expect(quotesModel.handleRuleEvents(mockEvents, mockData.headers, mockData.quoteRequest)) + .resolves + .toStrictEqual({ + terminate: false, + quoteRequest: mockData.quoteRequest, + headers: { + ...mockData.headers, + 'fspiop-destination': mockEvents[0].params.rerouteToFsp, + ...mockEvents[0].params.additionalHeaders + }, + additionalHeaders: mockEvents[0].params.additionalHeaders + }) + }) + }) + }) + }) + }) describe('validateQuoteRequest', () => { - it('should validate fspiopSource and fspiopDestination', async () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.validateQuoteRequest.mockRestore() + }) + + it('should validate payer and payee fspId for simple routing mode', async () => { expect.assertions(5) + const fspiopSource = 'dfsp1' const fspiopDestination = 'dfsp2' - const quoteRequest = { quoteId: 'uuid4' } expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() - await quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, quoteRequest) + await quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, mockData.quoteRequest, mockData.payer, mockData.payee) expect(quotesModel.db).toBeTruthy() // Constructor should have been called - expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) - expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(fspiopSource) - expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(fspiopDestination) + if (mockConfig.simpleRoutingMode) { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + } else { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(0) + } + expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(mockData.quoteRequest.payer.partyIdInfo.fspId) + expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(mockData.quoteRequest.payee.partyIdInfo.fspId) }) it('should throw internal error if no quoteRequest was supplied', async () => { - expect.assertions(5) + expect.assertions(4) + const fspiopSource = 'dfsp1' const fspiopDestination = 'dfsp2' const quoteRequest = undefined expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() - try { - await quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, quoteRequest) - } catch (err) { - expect(quotesModel.db).toBeTruthy() // Constructor should have been called - expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } - }) - }) + await expect(quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - describe('validateQuoteUpdate', () => { - it('should validate quote update', async () => { - const result = await quotesModel.validateQuoteUpdate() - expect(result).toBeNull() + expect(quotesModel.db).toBeTruthy() // Constructor should have been called + expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() }) - }) + it('should throw PAYER_FSP_ID_NOT_FOUND error if payer is not active', async () => { + expect.assertions(6) - describe('handleQuoteRequest', () => { - it('should forward quote request in simple routing mode', async () => { - expect.assertions(5) - Config.SIMPLE_ROUTING_MODE = true - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.forwardQuoteRequest = jest.fn() - mockChildSpan.isFinished = false + const fspiopSource = 'dfsp1' + const fspiopDestination = 'dfsp2' - const refs = await quotesModel.handleQuoteRequest(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() + expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() + const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 0 } + const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 1 } - let args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockSpan.getChild.mock.calls.length).toBe(1) - args = [{ headers, payload: quoteRequest }, EventSdk.AuditEventAction.start] - expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteRequest.quoteId, quoteRequest, mockChildSpan] - expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) - expect(refs).toEqual({}) + await expect(quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, mockData.quoteRequest, payer, payee)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.PAYER_FSP_ID_NOT_FOUND.code) + + expect(quotesModel.db).toBeTruthy() // Constructor should have been called + if (mockConfig.simpleRoutingMode) { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + } else { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(0) + } + expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(mockData.quoteRequest.payer.partyIdInfo.fspId) + expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(mockData.quoteRequest.payee.partyIdInfo.fspId) }) - it('should handle exception in simple routing mode', async () => { - expect.assertions(7) - Config.SIMPLE_ROUTING_MODE = true - quotesModel.validateQuoteRequest = jest.fn() - const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) - quotesModel.forwardQuoteRequest = jest.fn(() => { throw fspiopError }) - quotesModel.handleException = jest.fn() - mockChildSpan.isFinished = false + it('should throw DESTINATION_FSP_ERROR error if payee is not active', async () => { + expect.assertions(6) - const refs = await quotesModel.handleQuoteRequest(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() + const fspiopSource = 'dfsp1' + const fspiopDestination = 'dfsp2' - let args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockSpan.getChild.mock.calls.length).toBe(1) - args = [{ headers, payload: quoteRequest }, EventSdk.AuditEventAction.start] - expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteRequest.quoteId, quoteRequest, mockChildSpan] - expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) - args = [headers['fspiop-source'], quoteRequest.quoteId, fspiopError, headers, mockChildSpan] - expect(quotesModel.handleException).toBeCalledWith(...args) - expect(quotesModel.handleException.mock.calls.length).toBe(1) + expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() + const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 1 } + const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 0 } - expect(refs).toEqual({}) - }) - it('should throw modified request error when duplicate request is not a resend', async () => { - expect.assertions(8) - Config.SIMPLE_ROUTING_MODE = false - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { return { isDuplicateId: true, isResend: false } }) + await expect(quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, mockData.quoteRequest, payer, payee)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) - try { - await quotesModel.handleQuoteRequest(headers, quoteRequest, mockSpan) - } catch (err) { - const args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteRequest).toBeCalledWith(quoteRequest) - expect(mockTransaction.rollback.mock.calls.length).toBe(1) - expect(mockSpan.error.mock.calls[0][0]).toEqual(err) - expect(mockSpan.finish.mock.calls[0][0]).toEqual(err.message) - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST.code) + expect(quotesModel.db).toBeTruthy() // Constructor should have been called + if (mockConfig.simpleRoutingMode) { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + } else { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(0) } + expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(mockData.quoteRequest.payer.partyIdInfo.fspId) + expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(mockData.quoteRequest.payee.partyIdInfo.fspId) }) - it('should handle quote request resend when duplicate request matches original', async () => { - expect.assertions(5) - Config.SIMPLE_ROUTING_MODE = false - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { return { isDuplicateId: true, isResend: true } }) - quotesModel.handleQuoteRequestResend = jest.fn(() => 'handleQuoteRequestResendResult') - - const refs = await quotesModel.handleQuoteRequest(headers, quoteRequest, mockSpan) - - let args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteRequest).toBeCalledWith(quoteRequest) - args = [headers, quoteRequest, mockSpan] - expect(quotesModel.handleQuoteRequestResend).toBeCalledWith(...args) - expect(refs).toBe('handleQuoteRequestResendResult') - }) - it('should store to db and forward quote request when switch mode', async () => { - expect.assertions(12) - Config.SIMPLE_ROUTING_MODE = false - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') - const expected = { - transactionReferenceId: 'txRef', - transactionInitiatorTypeId: 'initiatorType', - transactionInitiatorId: 'initiator', - transactionScenarioId: 'scenario', - amountTypeId: 'amountTypeId', - quoteId: quoteRequest.quoteId, - payerId: quoteRequest.payer.partyIdInfo.fspId, - payeeId: quoteRequest.payee.partyIdInfo.fspId - } - mockDb.createTransactionReference.mockReturnValueOnce(expected.transactionReferenceId) - mockDb.getInitiatorType.mockReturnValueOnce(expected.transactionInitiatorTypeId) - mockDb.getInitiator.mockReturnValueOnce(expected.transactionInitiatorId) - mockDb.getScenario.mockReturnValueOnce(expected.transactionScenarioId) - mockDb.getAmountType.mockReturnValueOnce(expected.amountTypeId) - mockDb.createQuote.mockReturnValueOnce(expected.quoteId) - mockDb.createPayerQuoteParty.mockReturnValueOnce(expected.payerId) - mockDb.createPayeeQuoteParty.mockReturnValueOnce(expected.payeeId) - - RulesEngine.run = jest.fn(() => { - return { - events: [rules[0].event] - } - }) + it('should throw PAYER_ERROR error if payer does not have any active account', async () => { + expect.assertions(6) - quotesModel.forwardQuoteRequest = jest.fn() - mockChildSpan.isFinished = true + const fspiopSource = 'dfsp1' + const fspiopDestination = 'dfsp2' - const refs = await quotesModel.handleQuoteRequest(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() + expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() + const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 0 }], isActive: 1 } + const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }], isActive: 1 } - let args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteRequest).toBeCalledWith(quoteRequest) - expect(mockTransaction.rollback.mock.calls.length).toBe(0) - expect(mockTransaction.commit.mock.calls.length).toBe(1) - expect(RulesEngine.run.mock.calls.length).toBe(1) - expect(RulesEngine.run.mock.results[0].value.events.length).toBeGreaterThan(0) - expect(mockSpan.getChild.mock.calls.length).toBe(1) - args = [{ headers, payload: refs }, EventSdk.AuditEventAction.start] - expect(mockChildSpan.audit).toBeCalledWith(...args) - const forwardedHeaders = { - 'fspiop-source': 'dfsp1', - 'fspiop-destination': rules[0].event.params.rerouteToFsp + await expect(quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, mockData.quoteRequest, payer, payee)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.PAYER_ERROR.code) + + expect(quotesModel.db).toBeTruthy() // Constructor should have been called + if (mockConfig.simpleRoutingMode) { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + } else { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(0) } - args = [forwardedHeaders, refs.quoteId, quoteRequest, mockChildSpan] - expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) - expect(mockChildSpan.finish).not.toBeCalled() - expect(refs).toMatchObject(expected) + expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(mockData.quoteRequest.payer.partyIdInfo.fspId) + expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(mockData.quoteRequest.payee.partyIdInfo.fspId) }) - it('should store to db and forward quote request when switch mode and PAYEE is initiator', async () => { - expect.assertions(11) - Config.SIMPLE_ROUTING_MODE = false + it('should throw PAYEE_ERROR error if payee does not have any active account', async () => { + expect.assertions(6) - const localQuoteRequest = clone(quoteRequest) - localQuoteRequest.transactionType.initiator = 'PAYEE' - localQuoteRequest.geoCode = 'geoCodeId' - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') + const fspiopSource = 'dfsp1' + const fspiopDestination = 'dfsp2' - quotesModel.forwardQuoteRequest = jest.fn() - mockChildSpan.isFinished = true + expect(quotesModel.db.getParticipant).not.toHaveBeenCalled() // Validates mockClear() + const payee = { data: { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 0 }], isActive: 1 } } - const refs = await quotesModel.handleQuoteRequest(headers, localQuoteRequest, mockSpan) - await jest.runAllImmediates() + await expect(quotesModel.validateQuoteRequest(fspiopSource, fspiopDestination, mockData.quoteRequest, mockData.payer, payee)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.PAYEE_ERROR.code) - let args = [headers['fspiop-source'], headers['fspiop-destination'], localQuoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteRequest).toBeCalledWith(localQuoteRequest) - expect(mockTransaction.rollback.mock.calls.length).toBe(0) - expect(mockTransaction.commit.mock.calls.length).toBe(1) - expect(RulesEngine.run.mock.calls.length).toBe(1) - expect(mockSpan.getChild.mock.calls.length).toBe(1) - args = [{ headers, payload: refs }, EventSdk.AuditEventAction.start] - expect(mockChildSpan.audit).toBeCalledWith(...args) - const forwardedHeaders = { - 'fspiop-source': 'dfsp1', - 'fspiop-destination': rules[0].event.params.rerouteToFsp + expect(quotesModel.db).toBeTruthy() // Constructor should have been called + if (mockConfig.simpleRoutingMode) { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(2) + } else { + expect(quotesModel.db.getParticipant).toHaveBeenCalledTimes(0) } - args = [forwardedHeaders, refs.quoteId, localQuoteRequest, mockChildSpan] - expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) - expect(mockChildSpan.finish).not.toBeCalled() - expect(refs).toEqual({}) + expect(quotesModel.db.getParticipant.mock.calls[0][0]).toBe(mockData.quoteRequest.payer.partyIdInfo.fspId) + expect(quotesModel.db.getParticipant.mock.calls[1][0]).toBe(mockData.quoteRequest.payee.partyIdInfo.fspId) + }) + }) + describe('validateQuoteUpdate', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.validateQuoteUpdate.mockRestore() }) - it('should store to db and handle exception when forward quote request fails in switch mode', async () => { - expect.assertions(12) - Config.SIMPLE_ROUTING_MODE = false - - const localQuoteRequest = clone(quoteRequest) - localQuoteRequest.transactionType.subScenario = 'subScenario' - localQuoteRequest.expiration = new Date() - localQuoteRequest.transactionType.balanceOfPayments = 'balanceOfPayments' - localQuoteRequest.geoCode = 'geoCodeId' - quotesModel.validateQuoteRequest = jest.fn() - quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') - const expected = { - transactionReferenceId: 'txRef', - transactionInitiatorTypeId: 'initiatorType', - transactionInitiatorId: 'initiator', - transactionScenarioId: 'scenario', - amountTypeId: 'amountTypeId', - quoteId: localQuoteRequest.quoteId, - payerId: localQuoteRequest.payer.partyIdInfo.fspId, - payeeId: localQuoteRequest.payee.partyIdInfo.fspId, - transactionSubScenarioId: localQuoteRequest.transactionType.subScenario, - geoCodeId: localQuoteRequest.geoCode - } - mockDb.createTransactionReference.mockReturnValueOnce(expected.transactionReferenceId) - mockDb.getInitiatorType.mockReturnValueOnce(expected.transactionInitiatorTypeId) - mockDb.getInitiator.mockReturnValueOnce(expected.transactionInitiatorId) - mockDb.getScenario.mockReturnValueOnce(expected.transactionScenarioId) - mockDb.getAmountType.mockReturnValueOnce(expected.amountTypeId) - mockDb.createQuote.mockReturnValueOnce(expected.quoteId) - mockDb.createPayerQuoteParty.mockReturnValueOnce(expected.payerId) - mockDb.createPayeeQuoteParty.mockReturnValueOnce(expected.payeeId) - mockDb.createPayeeQuoteParty.mockReturnValueOnce(expected.payeeId) - mockDb.getSubScenario.mockReturnValueOnce(expected.transactionSubScenarioId) - mockDb.createGeoCode.mockReturnValueOnce(expected.geoCodeId) - - RulesEngine.run = jest.fn(() => { - return { - events: [] - } - }) - const customError = new Error('Custom error') - delete customError.stack - quotesModel.forwardQuoteRequest = jest.fn(() => { throw customError }) - quotesModel.handleException = jest.fn() - mockChildSpan.isFinished = false - - const refs = await quotesModel.handleQuoteRequest(headers, localQuoteRequest, mockSpan) - await jest.runAllImmediates() - let args = [headers['fspiop-source'], headers['fspiop-destination'], localQuoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteRequest).toBeCalledWith(localQuoteRequest) - expect(mockTransaction.rollback.mock.calls.length).toBe(0) - expect(mockTransaction.commit.mock.calls.length).toBe(1) - expect(RulesEngine.run.mock.results[0].value.events).toEqual([]) - expect(mockSpan.getChild.mock.calls.length).toBe(1) - args = [{ headers, payload: refs }, EventSdk.AuditEventAction.start] - expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, refs.quoteId, localQuoteRequest, mockChildSpan] - expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) - args = [headers['fspiop-source'], refs.quoteId, customError, headers, mockChildSpan] - expect(quotesModel.handleException).toBeCalledWith(...args) + it('should validate quote update', async () => { + const result = await quotesModel.validateQuoteUpdate() + expect(result).toBeNull() + }) + }) + describe('handleQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteRequest.mockRestore() + Util.fetchParticipantInfo.mockImplementationOnce(() => { return ({ payer: mockData.payer, payee: mockData.payee }) }) + }) - await jest.runAllImmediates() - expect(mockChildSpan.finish).toBeCalled() - expect(refs).toMatchObject(expected) + describe('Failures:', () => { + describe('Before forwarding the request:', () => { + it('throws an exception if `executeRules` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + quotesModel.executeRules = jest.fn(() => { throw fspiopError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toBe(fspiopError) + }) + it('throws an exception if `handleRuleEvents` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + quotesModel.handleRuleEvents = jest.fn(() => { throw fspiopError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toBe(fspiopError) + }) + it('stops execution and returns an undefined value if `handleRuleEvents` returns a truthy value for `terminate`', async () => { + expect.assertions(3) + + quotesModel.handleRuleEvents = jest.fn(() => { + return { + terminate: true + } + }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .resolves + .toBe(undefined) + expect(quotesModel.validateQuoteRequest).toHaveBeenCalledTimes(1) + expect(quotesModel.forwardQuoteRequest).not.toBeCalled() + }) + it('throws an exception if `validateQuoteRequest` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + quotesModel.validateQuoteRequest = jest.fn(() => { throw fspiopError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toBe(fspiopError) + }) + describe('In case environment is not configured for simple routing mode', () => { + beforeEach(() => { + mockConfig.simpleRoutingMode = false + }) + + it('throws an exception if `db.newTransaction` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.newTransaction = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `checkDuplicateQuoteRequest` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { throw fspiopError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toBe(fspiopError) + }) + it('throws an exception if the request is marked as duplicate and is instructed not to resend', async () => { + expect.assertions(1) + + quotesModel.checkDuplicateQuoteRequest = jest.fn(() => { + return { + isDuplicateId: true, + resend: false + } + }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST.code) + }) + it('throws an exception if `calculateRequestHash` fails', async () => { + expect.assertions(1) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + Util.calculateRequestHash.mockImplementationOnce(() => { throw fspiopError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toBe(fspiopError) + }) + it('throws an exception if `db.createQuoteDuplicateCheck` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createQuoteDuplicateCheck = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.createTransactionReference` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createTransactionReference = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.getInitiatorType` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.getInitiatorType = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.getInitiator` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.getInitiator = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.getScenario` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.getScenario = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + describe('In case a sub scenario is specified in the incoming quote request:', () => { + it('throws an exception if `db.getSubScenario` fails', async () => { + expect.assertions(1) + + mockData.quoteRequest.transactionType.subScenario = true + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.getSubScenario = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + }) + it('throws an exception if `db.getAmountType` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.getAmountType = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.createQuote` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createQuote = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.createPayerQuoteParty` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createPayerQuoteParty = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + it('throws an exception if `db.createPayeeQuoteParty` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createPayeeQuoteParty = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + describe('In case a `geoCode` exists in the incoming quote request:', () => { + it('throws an exception if `db.createGeoCode` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createGeoCode = jest.fn(() => { throw dbError }) + + mockData.quoteRequest.geoCode = { + latitude: '42.69751', + longitude: '23.32415' + } + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + }) + describe('In case a `extensionList` exists in the incoming quote request:', () => { + it('throws an exception if `db.createQuoteExtensions` fails', async () => { + expect.assertions(1) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + + quotesModel.db.createQuoteExtensions = jest.fn(() => { throw dbError }) + + mockData.quoteRequest.extensionList = { + extension: [{ + key: 'someKey', + value: 'someValue' + }] + } + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + }) + }) + it('throws an exception if `db.commit` of the returned DB transaction fails', async () => { + expect.assertions(2) + + const dbError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(dbError) + mockTransaction.commit = jest.fn(() => { throw dbError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + expect(mockTransaction.commit.mock.calls.length).toBe(1) + }) + }) + it('throws an exception if `span.getChild` fails', async () => { + expect.assertions(2) + + const spanError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(spanError) + mockSpan.getChild = jest.fn(() => { throw spanError }) + + await expect(quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toEqual(fspiopError) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + }) + }) + describe('While forwarding the request:', () => { + describe('In case environment is configured for simple routing mode', () => { + beforeEach(() => { + mockConfig.simpleRoutingMode = true + }) + + it('calls `handleException` with the proper arguments if `span.audit` fails', async () => { + expect.assertions(4) + + const spanError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(spanError) + mockChildSpan.audit = jest.fn(() => { throw spanError }) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], mockData.quoteId, fspiopError, mockData.headers, + mockChildSpan] + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(quotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(quotesModel.handleException.mock.calls.length).toBe(1) + expect(result).toEqual({}) + }) + + it('calls `handleException` with the proper arguments if `forwardQuoteRequest` fails', async () => { + expect.assertions(6) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + quotesModel.forwardQuoteRequest = jest.fn(() => { throw fspiopError }) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], mockData.quoteId, fspiopError, mockData.headers, + mockChildSpan] + const expectedForwardQuoteRequestArgs = [mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan] + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(quotesModel.forwardQuoteRequest.mock.calls.length).toBe(1) + expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...expectedForwardQuoteRequestArgs) + expect(quotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(quotesModel.handleException.mock.calls.length).toBe(1) + expect(result).toEqual({}) + }) + }) + describe('In case environment is not configured for simple routing mode', () => { + let expectedResult + + beforeEach(() => { + mockConfig.simpleRoutingMode = false + + expectedResult = { + amountTypeId: mockData.amountTypeId, + quoteId: mockData.quoteRequest.quoteId, + payerId: mockData.quoteRequest.payer.partyIdInfo.fspId, + payeeId: mockData.quoteRequest.payee.partyIdInfo.fspId, + transactionInitiatorTypeId: mockData.initiatorType, + transactionInitiatorId: mockData.initiator, + transactionReferenceId: mockData.transactionReference, + transactionScenarioId: mockData.scenario, + transactionSubScenarioId: mockData.quoteRequest.transactionType.subScenario, + geoCodeId: mockData.geoCode, + extensions: mockData.quoteRequest.extensionList.extension + } + }) + + it('calls `handleException` with the proper arguments if `span.audit` fails', async () => { + expect.assertions(4) + + const spanError = new Error('foo') + const fspiopError = ErrorHandler.ReformatFSPIOPError(spanError) + mockChildSpan.audit = jest.fn(() => { throw spanError }) + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], result.quoteId, fspiopError, + mockData.headers, mockChildSpan] + + expect(quotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(quotesModel.handleException.mock.calls.length).toBe(1) + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(result).toEqual(expectedResult) + }) + + it('calls `handleException` with the proper arguments if `forwardQuoteRequest` fails', async () => { + expect.assertions(6) + + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) + + quotesModel.forwardQuoteRequest = jest.fn(() => { throw fspiopError }) + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + const expectedHandleExceptionArgs = [mockData.headers['fspiop-source'], mockData.quoteId, fspiopError, mockData.headers, + mockChildSpan] + const expectedForwardQuoteRequestArgs = [mockData.headers, result.quoteId, mockData.quoteRequest, mockChildSpan, undefined] + + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(quotesModel.forwardQuoteRequest.mock.calls.length).toBe(1) + expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...expectedForwardQuoteRequestArgs) + expect(quotesModel.handleException).toBeCalledWith(...expectedHandleExceptionArgs) + expect(quotesModel.handleException.mock.calls.length).toBe(1) + expect(result).toEqual(expectedResult) + }) + }) + }) }) - it('should throw internal error when validation fails', async () => { - expect.assertions(4) - const customErrorNoStack = new Error('Custom error') - delete customErrorNoStack.stack - quotesModel.validateQuoteRequest = jest.fn(() => { throw customErrorNoStack }) + describe('Success:', () => { + describe('Before forwarding the request:', () => { + it('stops execution if `handleRuleEvents` returns a truthy value for `terminate`', async () => { + expect.assertions(2) + + jest.spyOn(quotesModel, 'handleRuleEvents').mockImplementation(jest.fn(() => { + return { + terminate: true + } + })) + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + expect(quotesModel.db.createQuoteDuplicateCheck.mock.calls.length).toBe(0) + expect(result).toBe(undefined) + }) + }) - try { - await quotesModel.handleQuoteRequest(headers, quoteRequest) - } catch (err) { - const args = [headers['fspiop-source'], headers['fspiop-destination'], quoteRequest] - expect(quotesModel.validateQuoteRequest).toBeCalledWith(...args) - expect(mockTransaction.rollback.mock.calls.length).toBe(0) - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + describe('While forwarding the request:', () => { + describe('In case environment is configured for simple routing mode', () => { + beforeEach(() => { + mockConfig.simpleRoutingMode = true + }) + + it('forwards the quote request properly', async () => { + expect.assertions(5) + + mockChildSpan.isFinished = false + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + const expectedValidateQuoteRequestArgs = [mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'], mockData.quoteRequest, mockData.payer, mockData.payee] + expect(quotesModel.validateQuoteRequest).toBeCalledWith(...expectedValidateQuoteRequestArgs) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + + const expectedAuditArgs = [{ headers: mockData.headers, payload: mockData.quoteRequest }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...expectedAuditArgs) + + const expectedForwardRequestArgs = [mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan] + expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...expectedForwardRequestArgs) + expect(result).toEqual({}) + }) + }) + describe('In case environment is not configured for simple routing mode', () => { + let expectedResult + + beforeEach(() => { + mockConfig.simpleRoutingMode = false + + expectedResult = { + amountTypeId: mockData.amountTypeId, + quoteId: mockData.quoteRequest.quoteId, + payerId: mockData.quoteRequest.payer.partyIdInfo.fspId, + payeeId: mockData.quoteRequest.payee.partyIdInfo.fspId, + transactionInitiatorTypeId: mockData.initiatorType, + transactionInitiatorId: mockData.initiator, + transactionReferenceId: mockData.transactionReference, + transactionScenarioId: mockData.scenario, + transactionSubScenarioId: mockData.quoteRequest.transactionType.subScenario, + geoCodeId: mockData.geoCode, + extensions: mockData.quoteRequest.extensionList.extension + } + }) + + it('calls all database create entity methods with correct arguments', async () => { + expect.assertions(8) + + const expectedHash = Util.calculateRequestHash(mockData.quoteRequest) + const mockCreateQuoteDuplicateCheckArgs = [mockTransaction, mockData.quoteRequest.quoteId, + expectedHash] + const mockCreateTransactionReferenceArgs = [mockTransaction, mockData.quoteRequest.quoteId, + mockData.quoteRequest.transactionId] + const mockCreateQuoteArgs = [mockTransaction, { + amount: '100.0000', + amountTypeId: 'fakeAmountTypeId', + balanceOfPaymentsId: null, + currencyId: 'USD', + expirationDate: null, + note: undefined, + quoteId: 'test123', + transactionInitiatorId: 'fakeInitiator', + transactionInitiatorTypeId: 'fakeInitiatorType', + transactionReferenceId: 'fakeTxRef', + transactionRequestId: null, + transactionScenarioId: 'fakeScenario', + transactionSubScenarioId: undefined + }] + const mockCreatePayerQuotePartyArgs = [mockTransaction, mockData.quoteRequest.quoteId, + mockData.quoteRequest.payer, mockData.quoteRequest.amount.amount, + mockData.quoteRequest.amount.currency] + const mockCreatePayeeQuotePartyArgs = [mockTransaction, mockData.quoteRequest.quoteId, + mockData.quoteRequest.payee, mockData.quoteRequest.amount.amount, + mockData.quoteRequest.amount.currency] + const mockCreateQuoteExtensionsArgs = [mockTransaction, + mockData.quoteRequest.extensionList.extension, + mockData.quoteRequest.quoteId, + mockData.quoteRequest.transactionId + ] + const mockCreateGeoCodeArgs = [mockTransaction, { + quotePartyId: mockData.quoteRequest.payer.partyIdInfo.fspId, + latitude: mockData.quoteRequest.geoCode.latitude, + longitude: mockData.quoteRequest.geoCode.longitude + }] + + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + expect(quotesModel.db.createQuoteDuplicateCheck).toBeCalledWith(...mockCreateQuoteDuplicateCheckArgs) + expect(quotesModel.db.createTransactionReference).toBeCalledWith(...mockCreateTransactionReferenceArgs) + expect(quotesModel.db.createQuote).toBeCalledWith(...mockCreateQuoteArgs) + expect(quotesModel.db.createPayerQuoteParty).toBeCalledWith(...mockCreatePayerQuotePartyArgs) + expect(quotesModel.db.createPayeeQuoteParty).toBeCalledWith(...mockCreatePayeeQuotePartyArgs) + expect(quotesModel.db.createQuoteExtensions).toBeCalledWith(...mockCreateQuoteExtensionsArgs) + expect(quotesModel.db.createGeoCode).toBeCalledWith(...mockCreateGeoCodeArgs) + + expect(result).toEqual(expectedResult) + }) + + it('forwards the quote request properly', async () => { + expect.assertions(5) + + mockChildSpan.isFinished = false + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + const expectedValidateQuoteRequestArgs = [mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'], mockData.quoteRequest, mockData.payer, mockData.payee] + expect(quotesModel.validateQuoteRequest).toBeCalledWith(...expectedValidateQuoteRequestArgs) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + + const expectedAuditArgs = [{ headers: mockData.headers, payload: expectedResult }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...expectedAuditArgs) + + const expectedForwardRequestArgs = [mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan, undefined] + expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...expectedForwardRequestArgs) + expect(result).toEqual(expectedResult) + }) + + it('forwards the quote request properly with additionalHeaders from the rules', async () => { + expect.assertions(5) + + quotesModel.handleRuleEvents = jest.fn(() => { + return { + terminate: false, + quoteRequest: mockData.quoteRequest, + headers: { + ...mockData.headers, + 'fspiop-destination': mockData.rules[0].event.params.rerouteToFsp, + ...mockData.rules[0].event.params.additionalHeaders + }, + additionalHeaders: mockData.rules[0].event.params.additionalHeaders + } + }) + + mockChildSpan.isFinished = false + const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) + + const expectedValidateQuoteRequestArgs = [mockData.headers['fspiop-source'], mockData.headers['fspiop-destination'], mockData.quoteRequest, mockData.payer, mockData.payee] + expect(quotesModel.validateQuoteRequest).toBeCalledWith(...expectedValidateQuoteRequestArgs) + expect(mockSpan.getChild.mock.calls.length).toBe(1) + + const expectedAuditArgs = [{ headers: mockData.headers, payload: expectedResult }, EventSdk.AuditEventAction.start] + expect(mockChildSpan.audit).toBeCalledWith(...expectedAuditArgs) + + const expectedForwardRequestArgs = [{ ...mockData.headers, 'fspiop-destination': mockData.rules[0].event.params.rerouteToFsp, ...mockData.rules[0].event.params.additionalHeaders }, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan, mockData.rules[0].event.params.additionalHeaders] + expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...expectedForwardRequestArgs) + expect(result).toEqual(expectedResult) + }) + }) + }) }) }) - describe('forwardQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.forwardQuoteRequest.mockRestore() + }) + it('should get http status code 202 Accepted in simple routing mode', async () => { - expect.assertions(3) - Config.SIMPLE_ROUTING_MODE = true - mockDb.getParticipantEndpoint.mockReturnValueOnce(endpoints.payeefsp) + expect.assertions(1) + mockConfig.simpleRoutingMode = true + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) - let err - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest, mockChildSpan) - } catch (e) { - err = e - } - expect(err).toBe(undefined) - expect(mockDb.getParticipantEndpoint).toBeCalled() - expect(mockDb.getQuotePartyEndpoint).not.toBeCalled() + await quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan) + + expect(quotesModel.db.getParticipantEndpoint).toBeCalled() + // expect(quotesModel.db.getQuotePartyEndpoint).not.toBeCalled() }) it('should get http status code 202 Accepted in switch mode', async () => { - expect.assertions(3) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.payeefsp) + expect.assertions(1) - let err - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest, mockChildSpan) - } catch (e) { - err = e - } - expect(err).toBe(undefined) - expect(mockDb.getParticipantEndpoint).not.toBeCalled() - expect(mockDb.getQuotePartyEndpoint).toBeCalled() + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + + await quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan) + + expect(quotesModel.db.getParticipantEndpoint).toBeCalled() + // expect(quotesModel.db.getQuotePartyEndpoint).toBeCalled() }) it('should throw when quoteRequest is undefined', async () => { - expect.assertions(2) - try { - const originalQuoteRequest = undefined - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, originalQuoteRequest, mockChildSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + expect.assertions(1) + + await expect(quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, undefined, mockChildSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) }) it('should throw when participant endpoint is not found', async () => { - expect.assertions(2) - Config.SIMPLE_ROUTING_MODE = false - const endpoint = undefined - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoint) - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest, mockChildSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) - } + expect.assertions(1) + + mockConfig.simpleRoutingMode = false + + quotesModel.db.getQuotePartyEndpoint.mockReturnValueOnce(undefined) + + await expect(quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) }) it('should not use spans when undefined and should throw when participant endpoint is invalid', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.invalid) - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) - } + expect.assertions(3) + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalid) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) it('should throw when participant endpoint returns invalid response', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.invalidResponse) - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) - } + expect.assertions(3) + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalidResponse) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) it('should inspect and throw custom error as FSPIOPerror', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(3) + + mockConfig.simpleRoutingMode = false const customErrorNoStack = new Error('Custom error') delete customErrorNoStack.stack - mockDb.getQuotePartyEndpoint.mockRejectedValueOnce(customErrorNoStack) - try { - await quotesModel.forwardQuoteRequest(headers, quoteRequest.quoteId, quoteRequest) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + quotesModel.db.getParticipantEndpoint.mockRejectedValueOnce(customErrorNoStack) + + await expect(quotesModel.forwardQuoteRequest(mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) }) - describe('handleQuoteRequestResend', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteRequestResend.mockRestore() + }) + it('forward quote request', async () => { expect.assertions(5) mockChildSpan.isFinished = false - quotesModel.forwardQuoteRequest = jest.fn() - let err - try { - await quotesModel.handleQuoteRequestResend(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() - await flushPromises() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteRequestResend(mockData.headers, mockData.quoteRequest, mockSpan)) + .resolves + .toBe(undefined) + expect(mockSpan.getChild).toBeCalled() expect(mockChildSpan.audit).toBeCalled() - const args = [headers, quoteRequest.quoteId, quoteRequest, mockChildSpan] + const args = [mockData.headers, mockData.quoteRequest.quoteId, mockData.quoteRequest, mockChildSpan, undefined] expect(quotesModel.forwardQuoteRequest).toBeCalledWith(...args) expect(mockChildSpan.finish).toBeCalled() }) @@ -678,467 +1377,1097 @@ describe('quotesModel', () => { mockChildSpan.isFinished = true const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) quotesModel.forwardQuoteRequest = jest.fn(() => { throw fspiopError }) - quotesModel.handleException = jest.fn() - let err - try { - await quotesModel.handleQuoteRequestResend(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteRequestResend(mockData.headers, mockData.quoteRequest, mockSpan)) + .resolves + .toBe(undefined) + expect(mockChildSpan.audit).toBeCalled() - const args = [headers['fspiop-source'], quoteRequest.quoteId, fspiopError, headers, mockChildSpan] + const args = [mockData.headers['fspiop-source'], mockData.quoteRequest.quoteId, fspiopError, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() }) it('handle custom error without stack when forward quote fails', async () => { expect.assertions(4) + + mockChildSpan.isFinished = true const customErrorNoStack = new Error('Custom error') delete customErrorNoStack.stack quotesModel.forwardQuoteRequest = jest.fn(() => { throw customErrorNoStack }) - quotesModel.handleException = jest.fn() - let err - try { - await quotesModel.handleQuoteRequestResend(headers, quoteRequest, mockSpan) - await jest.runAllImmediates() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteRequestResend(mockData.headers, mockData.quoteRequest, mockSpan)) + .resolves + .toBe(undefined) + expect(mockChildSpan.audit).toBeCalled() - const args = [headers['fspiop-source'], quoteRequest.quoteId, customErrorNoStack, headers, mockChildSpan] + const args = [mockData.headers['fspiop-source'], mockData.quoteRequest.quoteId, customErrorNoStack, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() }) it('handle custom error without stack when writeLog fails', async () => { expect.assertions(1) + const errorMessage = 'Custom error' const customErrorNoStack = new Error(errorMessage) delete customErrorNoStack.stack quotesModel.writeLog = jest.fn(() => { throw customErrorNoStack }) - try { - await quotesModel.handleQuoteRequestResend(headers, quoteRequest, mockSpan) - } catch (err) { - expect(err.message).toBe(errorMessage) - } + await expect(quotesModel.handleQuoteRequestResend(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toHaveProperty('message', errorMessage) }) it('handle custom error without stack when writeLog fails', async () => { - expect.assertions(2) + expect.assertions(1) + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) quotesModel.writeLog = jest.fn().mockImplementationOnce(cb => cb(fspiopError)) - try { - await quotesModel.handleQuoteRequestResend(headers, quoteRequest, mockSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + await expect(quotesModel.handleQuoteRequestResend(mockData.headers, mockData.quoteRequest, mockSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) }) }) - describe('handleQuoteUpdate', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteUpdate.mockRestore() + }) + it('should forward quote update in simple routing mode', async () => { expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = true - quotesModel.forwardQuoteUpdate = jest.fn() + + mockConfig.simpleRoutingMode = true mockChildSpan.isFinished = false - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() - await flushPromises() + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) expect(mockSpan.getChild.mock.calls.length).toBe(1) - let args = [{ headers, params: { quoteId }, payload: quoteUpdate }, EventSdk.AuditEventAction.start] + let args = [{ headers: mockData.headers, params: { quoteId: mockData.quoteRequest.quoteId }, payload: mockData.quoteUpdate }, EventSdk.AuditEventAction.start] expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteId, quoteUpdate, mockChildSpan] + args = [mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) expect(refs).toEqual({}) }) it('should handle exception in simple routing mode', async () => { expect.assertions(6) - Config.SIMPLE_ROUTING_MODE = true + + mockConfig.simpleRoutingMode = true const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) quotesModel.forwardQuoteUpdate = jest.fn(() => { throw fspiopError }) - quotesModel.handleException = jest.fn() mockChildSpan.isFinished = false - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) expect(mockSpan.getChild.mock.calls.length).toBe(1) - let args = [{ headers, params: { quoteId }, payload: quoteUpdate }, EventSdk.AuditEventAction.start] + let args = [{ headers: mockData.headers, params: { quoteId: mockData.quoteRequest.quoteId }, payload: mockData.quoteUpdate }, EventSdk.AuditEventAction.start] expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteId, quoteUpdate, mockChildSpan] + args = [mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) - args = [headers['fspiop-source'], quoteId, fspiopError, headers, mockChildSpan] + args = [mockData.headers['fspiop-source'], mockData.quoteId, fspiopError, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(quotesModel.handleException.mock.calls.length).toBe(1) expect(refs).toEqual({}) }) it('should throw modified update error when duplicate update is not a resend', async () => { - expect.assertions(7) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(5) + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: true, isResend: false } }) try { - await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) + await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) } catch (err) { - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(quoteId, quoteUpdate) - expect(mockTransaction.rollback.mock.calls.length).toBe(1) - expect(mockSpan.error.mock.calls[0][0]).toEqual(err) - expect(mockSpan.finish.mock.calls[0][0]).toEqual(err.message) + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(0) + expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(mockData.quoteId, mockData.quoteUpdate) + expect(mockTransaction.rollback.mock.calls.length).toBe(0) expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST.code) } }) it('should handle quote update resend when duplicate update matches original', async () => { expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: true, isResend: true } }) quotesModel.handleQuoteUpdateResend = jest.fn(() => 'handleQuoteUpdateResendResult') - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(quoteId, quoteUpdate) - const args = [headers, quoteId, quoteUpdate, mockSpan] + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(0) + expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(mockData.quoteId, mockData.quoteUpdate) + const args = [mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan] expect(quotesModel.handleQuoteUpdateResend).toBeCalledWith(...args) expect(refs).toBe('handleQuoteUpdateResendResult') }) it('should store to db and forward quote update when switch mode', async () => { - expect.assertions(9) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(10) + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') + Util.calculateRequestHash = jest.fn(() => 'hash') + + const mockQuoteResponseId = 'resp123' + const expected = { - quoteResponseId: 'resp123' + quoteResponseId: mockQuoteResponseId, + extensions: mockData.quoteUpdate.extensionList.extension } - mockDb.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) - quotesModel.forwardQuoteUpdate = jest.fn() + + quotesModel.db.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) mockChildSpan.isFinished = true - const localQuoteUpdate = clone(quoteUpdate) + + const localQuoteUpdate = clone(mockData.quoteUpdate) delete localQuoteUpdate.geoCode - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, localQuoteUpdate, mockSpan) - await jest.runAllImmediates() + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, localQuoteUpdate, mockSpan) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(quoteId, localQuoteUpdate) + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(1) + expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(mockData.quoteId, localQuoteUpdate) expect(mockTransaction.rollback.mock.calls.length).toBe(0) expect(mockTransaction.commit.mock.calls.length).toBe(1) expect(mockSpan.getChild.mock.calls.length).toBe(1) - let args = [{ headers, params: { quoteId }, payload: localQuoteUpdate }, EventSdk.AuditEventAction.start] + + expect(quotesModel.db.createQuoteExtensions).toBeCalledWith( + mockTransaction, + mockData.quoteUpdate.extensionList.extension, + mockData.quoteId, + null, + mockQuoteResponseId + ) + + let args = [{ headers: mockData.headers, params: { quoteId: mockData.quoteRequest.quoteId }, payload: localQuoteUpdate }, EventSdk.AuditEventAction.start] expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteId, localQuoteUpdate, mockChildSpan] + + args = [mockData.headers, mockData.quoteId, localQuoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() expect(refs).toMatchObject(expected) }) it('should store to db and forward quote update with geoCode in switch mode', async () => { expect.assertions(9) - Config.SIMPLE_ROUTING_MODE = false + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') + Util.calculateRequestHash = jest.fn(() => 'hash') const expected = { quoteResponseId: 'resp123', - geoCodeId: 'geoCodeId' + geoCodeId: 'geoCodeId', + extensions: mockData.quoteUpdate.extensionList.extension } - mockDb.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) - mockDb.createGeoCode.mockReturnValueOnce(expected.geoCodeId) - mockDb.getQuoteParty.mockReturnValueOnce('quotePartyRecord') - quotesModel.forwardQuoteUpdate = jest.fn() + quotesModel.db.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) + quotesModel.db.createGeoCode.mockReturnValueOnce(expected.geoCodeId) + quotesModel.db.getQuoteParty.mockReturnValueOnce('quotePartyRecord') mockChildSpan.isFinished = true - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(quoteId, quoteUpdate) + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(1) + expect(quotesModel.checkDuplicateQuoteResponse).toBeCalledWith(mockData.quoteId, mockData.quoteUpdate) expect(mockTransaction.rollback.mock.calls.length).toBe(0) expect(mockTransaction.commit.mock.calls.length).toBe(1) expect(mockSpan.getChild.mock.calls.length).toBe(1) - let args = [{ headers, params: { quoteId }, payload: quoteUpdate }, EventSdk.AuditEventAction.start] + let args = [{ headers: mockData.headers, params: { quoteId: mockData.quoteRequest.quoteId }, payload: mockData.quoteUpdate }, EventSdk.AuditEventAction.start] expect(mockChildSpan.audit).toBeCalledWith(...args) - args = [headers, quoteId, quoteUpdate, mockChildSpan] + args = [mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() expect(refs).toEqual(expected) }) it('should store to db and handle exception when forward quote update fails in switch mode', async () => { expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') + Util.calculateRequestHash = jest.fn(() => 'hash') const expected = { quoteResponseId: 'resp123', - geoCodeId: 'geoCodeId' + geoCodeId: 'geoCodeId', + extensions: mockData.quoteUpdate.extensionList.extension } - mockDb.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) - mockDb.createGeoCode.mockReturnValueOnce(expected.geoCodeId) - mockDb.getQuoteParty.mockReturnValueOnce('quotePartyRecord') + quotesModel.db.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) + quotesModel.db.createGeoCode.mockReturnValueOnce(expected.geoCodeId) + quotesModel.db.getQuoteParty.mockReturnValueOnce('quotePartyRecord') const customError = new Error('Custom error') delete customError.stack quotesModel.forwardQuoteUpdate = jest.fn(() => { throw customError }) - quotesModel.handleException = jest.fn() mockChildSpan.isFinished = true - const localQuoteUpdate = clone(quoteUpdate) + const localQuoteUpdate = clone(mockData.quoteUpdate) delete localQuoteUpdate.expiration - const refs = await quotesModel.handleQuoteUpdate(headers, quoteId, localQuoteUpdate, mockSpan) - await jest.runAllImmediates() + const refs = await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, localQuoteUpdate, mockSpan) - let args = [headers, quoteId, localQuoteUpdate, mockChildSpan] + let args = [mockData.headers, mockData.quoteId, localQuoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) - args = [headers['fspiop-source'], quoteId, customError, headers, mockChildSpan] + args = [mockData.headers['fspiop-source'], mockData.quoteId, customError, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() expect(refs).toEqual(expected) }) it('should throw partyNotFound error when getQuoteParty coldn\'t find a record in switch mode', async () => { - expect.assertions(6) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(4) + + mockConfig.simpleRoutingMode = false quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { return { isDuplicateId: false, isResend: false } }) - quotesModel.calculateRequestHash = jest.fn(() => 'hash') + Util.calculateRequestHash = jest.fn(() => 'hash') const expected = { quoteResponseId: 'resp123', geoCodeId: 'geoCodeId' } - mockDb.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) - mockDb.createGeoCode.mockReturnValueOnce(expected.geoCodeId) + quotesModel.db.createQuoteResponse.mockReturnValueOnce({ quoteResponseId: expected.quoteResponseId }) + quotesModel.db.createGeoCode.mockReturnValueOnce(expected.geoCodeId) try { - await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) + await quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan) } catch (err) { - expect(mockDb.newTransaction.mock.calls.length).toBe(1) + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(1) expect(mockTransaction.rollback.mock.calls.length).toBe(1) - expect(mockSpan.error.mock.calls[0][0]).toEqual(err) - expect(mockSpan.finish.mock.calls[0][0]).toEqual(err.message) expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND.code) } }) it('should throw validationError when headers contains accept', async () => { - expect.assertions(4) - const localHeaders = clone(headers) + expect.assertions(3) + + const localHeaders = clone(mockData.headers) localHeaders.accept = 'application/vnd.interoperability.quotes+json;version=1.0' - try { - await quotesModel.handleQuoteUpdate(localHeaders, quoteId, quoteUpdate) - } catch (err) { - expect(mockDb.newTransaction.mock.calls.length).toBe(0) - expect(mockTransaction.rollback.mock.calls.length).toBe(0) - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR.code) - } + await expect(quotesModel.handleQuoteUpdate(localHeaders, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR.code) + + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(0) + expect(mockTransaction.rollback.mock.calls.length).toBe(0) }) it('should store to db and throw custom error without error stack in switch mode', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(3) + + mockConfig.simpleRoutingMode = false const customErrorNoStack = new Error('Custom error') delete customErrorNoStack.stack quotesModel.checkDuplicateQuoteResponse = jest.fn(() => { throw customErrorNoStack }) - try { - await quotesModel.handleQuoteUpdate(headers, quoteId, quoteUpdate, mockSpan) - } catch (err) { - expect(mockDb.newTransaction.mock.calls.length).toBe(1) - expect(mockTransaction.rollback.mock.calls.length).toBe(1) - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + await expect(quotesModel.handleQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(0) + expect(mockTransaction.rollback.mock.calls.length).toBe(0) }) }) - describe('forwardQuoteUpdate', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.forwardQuoteUpdate.mockRestore() + }) + it('should get http status code 200 OK in simple routing mode', async () => { expect.assertions(3) - Config.SIMPLE_ROUTING_MODE = true - mockDb.getParticipantEndpoint.mockReturnValueOnce(endpoints.payeefsp) + mockConfig.simpleRoutingMode = true + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) - let err - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate, mockChildSpan) - } catch (e) { - err = e - } - expect(err).toBe(undefined) - expect(mockDb.getParticipantEndpoint).toBeCalled() - expect(mockDb.getQuotePartyEndpoint).not.toBeCalled() + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan)) + .resolves + .toBe(undefined) + + expect(quotesModel.db.getParticipantEndpoint).toBeCalled() + expect(quotesModel.db.getQuotePartyEndpoint).not.toBeCalled() }) it('should get http status code 200 OK in switch mode', async () => { expect.assertions(3) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.payeefsp) - let err - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate, mockChildSpan) - } catch (e) { - err = e - } - expect(err).toBe(undefined) - expect(mockDb.getParticipantEndpoint).not.toBeCalled() - expect(mockDb.getQuotePartyEndpoint).toBeCalled() + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan)) + .resolves + .toBe(undefined) + + expect(quotesModel.db.getParticipantEndpoint).toBeCalled() + expect(quotesModel.db.getQuotePartyEndpoint).not.toBeCalled() }) it('should throw when quoteUpdate is undefined', async () => { - expect.assertions(2) - try { - const originalQuoteUpdate = undefined - await quotesModel.forwardQuoteUpdate(headers, quoteId, originalQuoteUpdate, mockChildSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + expect.assertions(1) + + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, undefined, mockChildSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) }) it('should throw when participant endpoint is not found', async () => { - expect.assertions(2) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(1) + + mockConfig.simpleRoutingMode = false const endpoint = undefined - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoint) + quotesModel.db.getQuotePartyEndpoint.mockReturnValueOnce(endpoint) quotesModel.sendErrorCallback = jest.fn((_, fspiopError) => { throw fspiopError }) - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate, mockChildSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) - } + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR.code) }) it('should not use spans when undefined and should throw when participant endpoint is invalid', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.invalid) - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) - } + expect.assertions(3) + + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalid) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) it('should throw when participant endpoint returns invalid response', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false - mockDb.getQuotePartyEndpoint.mockReturnValueOnce(endpoints.invalidResponse) - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) - } + expect.assertions(3) + + mockConfig.simpleRoutingMode = false + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.invalidResponse) + Http.httpRequest.mockImplementationOnce(() => { throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR) }) + + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) it('should inspect and throw custom error as FSPIOPerror', async () => { - expect.assertions(4) - Config.SIMPLE_ROUTING_MODE = false + expect.assertions(3) + + mockConfig.simpleRoutingMode = false const customErrorNoStack = new Error('Custom error') delete customErrorNoStack.stack - mockDb.getQuotePartyEndpoint.mockRejectedValueOnce(customErrorNoStack) - try { - await quotesModel.forwardQuoteUpdate(headers, quoteId, quoteUpdate) - } catch (err) { - expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() - expect(mockChildSpan.audit).not.toHaveBeenCalled() - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) - } + quotesModel.db.getParticipantEndpoint.mockRejectedValueOnce(customErrorNoStack) + + await expect(quotesModel.forwardQuoteUpdate(mockData.headers, mockData.quoteId, mockData.quoteUpdate)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + + expect(mockChildSpan.injectContextToHttpRequest).not.toHaveBeenCalled() + expect(mockChildSpan.audit).not.toHaveBeenCalled() }) }) - describe('handleQuoteUpdateResend', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteUpdateResend.mockRestore() + }) + it('forward quote update', async () => { expect.assertions(5) + mockChildSpan.isFinished = false - quotesModel.forwardQuoteUpdate = jest.fn() - let err - try { - await quotesModel.handleQuoteUpdateResend(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() - await flushPromises() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteUpdateResend(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .resolves + .toBe(undefined) + expect(mockSpan.getChild).toBeCalled() expect(mockChildSpan.audit).toBeCalled() - const args = [headers, quoteId, quoteUpdate, mockChildSpan] + const args = [mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockChildSpan] expect(quotesModel.forwardQuoteUpdate).toBeCalledWith(...args) expect(mockChildSpan.finish).toBeCalled() }) it('handle fspiopError when forward quote fails', async () => { expect.assertions(4) + mockChildSpan.isFinished = true const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) quotesModel.forwardQuoteUpdate = jest.fn(() => { throw fspiopError }) - quotesModel.handleException = jest.fn() - let err - try { - await quotesModel.handleQuoteUpdateResend(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteUpdateResend(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .resolves + .toBe(undefined) + expect(mockChildSpan.audit).toBeCalled() - const args = [headers['fspiop-source'], quoteId, fspiopError, headers, mockChildSpan] + const args = [mockData.headers['fspiop-source'], mockData.quoteId, fspiopError, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() }) it('handle custom error without stack when forward quote fails', async () => { expect.assertions(4) + + mockChildSpan.isFinished = true const customErrorNoStack = new Error('Custom error') delete customErrorNoStack.stack quotesModel.forwardQuoteUpdate = jest.fn(() => { throw customErrorNoStack }) - quotesModel.handleException = jest.fn() - let err - try { - await quotesModel.handleQuoteUpdateResend(headers, quoteId, quoteUpdate, mockSpan) - await jest.runAllImmediates() - } catch (e) { - err = e - } - expect(err).toBe(undefined) + await expect(quotesModel.handleQuoteUpdateResend(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .resolves + .toBe(undefined) + expect(mockChildSpan.audit).toBeCalled() - const args = [headers['fspiop-source'], quoteId, customErrorNoStack, headers, mockChildSpan] + const args = [mockData.headers['fspiop-source'], mockData.quoteId, customErrorNoStack, mockData.headers, mockChildSpan] expect(quotesModel.handleException).toBeCalledWith(...args) expect(mockChildSpan.finish).not.toBeCalled() }) it('handle custom error without stack when writeLog fails', async () => { expect.assertions(1) + const errorMessage = 'Custom error' const customErrorNoStack = new Error(errorMessage) delete customErrorNoStack.stack quotesModel.writeLog = jest.fn(() => { throw customErrorNoStack }) - try { - await quotesModel.handleQuoteUpdateResend(headers, quoteId, quoteUpdate, mockSpan) - } catch (err) { - expect(err.message).toBe(errorMessage) - } + await expect(quotesModel.handleQuoteUpdateResend(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .rejects + .toHaveProperty('message', errorMessage) }) it('handle custom error without stack when writeLog fails', async () => { - expect.assertions(2) + expect.assertions(1) + const fspiopError = ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR) quotesModel.writeLog = jest.fn().mockImplementationOnce(cb => cb(fspiopError)) - try { - await quotesModel.handleQuoteUpdateResend(headers, quoteId, quoteUpdate, mockSpan) - } catch (err) { - expect(err instanceof ErrorHandler.Factory.FSPIOPError).toBeTruthy() - expect(err.apiErrorCode.code).toBe(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + await expect(quotesModel.handleQuoteUpdateResend(mockData.headers, mockData.quoteId, mockData.quoteUpdate, mockSpan)) + .rejects + .toHaveProperty('apiErrorCode.code', ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR.code) + }) + }) + + describe('handleQuoteError', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteError.mockRestore() + }) + + it('handles the quote error', async () => { + // Arrange + expect.assertions(2) + mockConfig.simpleRoutingMode = true + const error = { + errorCode: 2001, + errorDescription: 'Test Error' + } + + // Act + const result = await quotesModel.handleQuoteError(mockData.headers, mockData.quoteId, error, mockSpan) + + // Assert + // For `handleQuoteError` response is undefined + expect(result).toBe(undefined) + expect(quotesModel.sendErrorCallback).toHaveBeenCalledTimes(1) + }) + + it('sends the error callback to the correct destination', async () => { + // Arrange + expect.assertions(3) + mockConfig.simpleRoutingMode = true + const error = { + errorCode: 2001, + errorDescription: 'Test Error' + } + quotesModel.sendErrorCallback = jest.fn() + + // Act + const result = await quotesModel.handleQuoteError(mockData.headers, mockData.quoteId, error, mockSpan) + + // Assert + // For `handleQuoteError` response is undefined + expect(result).toBe(undefined) + expect(quotesModel.sendErrorCallback).toHaveBeenCalledTimes(1) + expect(quotesModel.sendErrorCallback.mock.calls[0][0]) + .toEqual(mockData.headers[Enum.Http.Headers.FSPIOP.DESTINATION]) + }) + + it('handles the quote error with simpleRoutingMode: false', async () => { + // Arrange + expect.assertions(4) + mockConfig.simpleRoutingMode = false + const error = { + errorCode: 2001, + errorDescription: 'Test Error' + } + + // Act + const result = await quotesModel.handleQuoteError(mockData.headers, mockData.quoteId, error, mockSpan) + + // Assert + expect(result).toBe(mockData.quoteId) + expect(quotesModel.sendErrorCallback).toHaveBeenCalledTimes(1) + expect(quotesModel.db.newTransaction.mock.calls.length).toBe(1) + expect(quotesModel.db.createQuoteError.mock.calls.length).toBe(1) + }) + + it('handles bad error input', async () => { + // Arrange + expect.assertions(1) + mockConfig.simpleRoutingMode = false + const error = { + errorDescription: 'Test Error' + } + + const errorMessage = { + message: 'Test Error' + } + + // Act + const action = async () => quotesModel.handleQuoteError(mockData.headers, mockData.quoteId, error, mockSpan) + + // const es = 'Factory function createFSPIOPError failed due to apiErrorCode being invalid' + // Assert + await expect(action()).rejects.toThrowError(`Factory function createFSPIOPError failed due to apiErrorCode being invalid - ${JSON.stringify(errorMessage)}.`) + }) + }) + + describe('handleQuoteGet', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleQuoteGet.mockRestore() + }) + + it('handles the quote get with a child span', async () => { + // Arrange + expect.assertions(3) + // Act + await quotesModel.handleQuoteGet(mockData.headers, mockData.quoteId, mockSpan) + + // Assert + expect(mockChildSpan.audit.mock.calls.length).toBe(1) + expect(mockChildSpan.finish.mock.calls.length).toBe(1) + expect(quotesModel.forwardQuoteGet.mock.calls.length).toBe(1) + }) + + it('handles an exception on `span.getChild`', async () => { + // Arrange + expect.assertions(1) + mockSpan.getChild = jest.fn(() => { throw new Error('Test Error') }) + + // Act + const action = async () => quotesModel.handleQuoteGet(mockData.headers, mockData.quoteId, mockSpan) + + // Assert + await expect(action()).rejects.toThrowError('Test Error') + }) + + it('handles an exception on `childSpan.audit`', async () => { + // Arrange + expect.assertions(2) + mockChildSpan.audit = jest.fn(() => { throw new Error('Test Error') }) + + // Act + await quotesModel.handleQuoteGet(mockData.headers, mockData.quoteId, mockSpan) + + // Assert + expect(mockChildSpan.finish.mock.calls.length).toBe(1) + expect(quotesModel.handleException.mock.calls.length).toBe(1) + }) + }) + + describe('forwardQuoteGet', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.forwardQuoteGet.mockRestore() + }) + + it('fails to forward if the database has no endpoint for the dfsp', async () => { + // Arrange + expect.assertions(1) + quotesModel.db.getParticipantEndpoint.mockImplementation(() => null) + + // Act + const action = async () => quotesModel.forwardQuoteGet(mockData.headers, mockData.quoteId, mockSpan) + + // Assert + await expect(action()).rejects.toThrowError('No FSPIOP_CALLBACK_URL_QUOTES found for quote GET test123') + }) + + it('forwards the request to the payee dfsp without a span', async () => { + // Arrange + // expect.assertions(2) + quotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + const expectedOptions = { + headers: {}, + method: 'GET', + url: 'http://localhost:3333/quotes/test123' + } + Util.generateRequestHeaders.mockImplementationOnce(() => { + return {} + }) + // Act + await quotesModel.forwardQuoteGet(mockData.headers, mockData.quoteId) + + // Assert + expect(Http.httpRequest).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledWith(expectedOptions, mockData.headers[Enum.Http.Headers.FSPIOP.SOURCE]) + }) + + it('forwards the request to the payee dfsp', async () => { + // Arrange + expect.assertions(4) + quotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345' + } + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + headers: { + spanHeaders: '12345' + } + } + + // Act + await quotesModel.forwardQuoteGet(mockData.headers, mockData.quoteId, mockSpan) + + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledTimes(1) + expect(Http.httpRequest).toBeCalledWith(expectedOptions, mockData.headers[Enum.Http.Headers.FSPIOP.SOURCE]) + }) + + it('handles a http error', async () => { + // Arrange + expect.assertions(1) + quotesModel.db.getParticipantEndpoint.mockImplementation(() => 'http://localhost:3333') + Http.httpRequest.mockImplementationOnce(() => { throw new Error('Test HTTP Error') }) + + // Act + const action = async () => quotesModel.forwardQuoteGet(mockData.headers, mockData.quoteId) + + // Assert + await expect(action()).rejects.toThrowError('Test HTTP Error') + }) + }) + + describe('handleException', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.handleException.mockRestore() + }) + + it('handles the error and finishes the child span', async () => { + // Arrange + expect.assertions(3) + const error = new Error('Test Error') + const expectedError = ErrorHandler.ReformatFSPIOPError(error) + quotesModel.sendErrorCallback.mockImplementationOnce(() => true) + + // Act + const result = await quotesModel.handleException('payeefsp', mockData.quoteId, error, mockData.headers, mockSpan) + + // Assert + expect(quotesModel.sendErrorCallback).toHaveBeenCalledWith('payeefsp', expectedError, mockData.quoteId, mockData.headers, mockChildSpan, true) + expect(result).toBe(true) + expect(mockChildSpan.finish).toHaveBeenCalledTimes(1) + }) + + it('handles an error in sendErrorCallback', async () => { + // Arrange + expect.assertions(3) + const error = new Error('Test Error') + const expectedError = ErrorHandler.ReformatFSPIOPError(error) + quotesModel.sendErrorCallback.mockImplementationOnce(() => { throw new Error('Error sending callback.') }) + + // Act + await quotesModel.handleException('payeefsp', mockData.quoteId, error, mockData.headers, mockSpan) + + // Assert + expect(quotesModel.sendErrorCallback).toHaveBeenCalledWith('payeefsp', expectedError, mockData.quoteId, mockData.headers, mockChildSpan, true) + expect(quotesModel.writeLog).toHaveBeenCalledTimes(1) + expect(mockChildSpan.finish).toHaveBeenCalledTimes(1) + }) + }) + + describe('sendErrorCallback', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.sendErrorCallback.mockRestore() + }) + + it('sends the error callback without a span', async () => { + // Arrange + expect.assertions(1) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: JSON.stringify(fspiopError.toApiErrorObject(mockConfig.errorHandling), LibUtil.getCircularReplacer()), + headers: {} + } + + // Act + await quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers) + + // Assert + expect(axios.request).toBeCalledWith(expectedOptions) + }) + + it('sends the error callback and handles the span', async () => { + // Arrange + expect.assertions(3) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345' + } + } + + // Act + await quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers, mockSpan) + + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(axios.request).toBeCalledWith(expectedOptions) + }) + + it('sends the error callback JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + // expect.assertions(6) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + mockConfig.jws.jwsSign = true + mockConfig.jws.jwsSigningKey = jwsSigningKey + // Act + await quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers, mockSpan, true) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).toBeCalledTimes(1) + expect(axios.request.mock.calls[0][0].headers).toHaveProperty('fspiop-signature') + expect(axios.request.mock.calls[0][0].headers['fspiop-signature']).toEqual(expect.stringContaining('signature')) + expect(axios.request.mock.calls[0][0].headers['fspiop-signature']).toEqual(expect.stringContaining('protectedHeader')) + jwsSignSpy.mockRestore() + }) + + it('sends the error callback NOT JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + expect.assertions(5) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + } + } + mockConfig.jws.jwsSign = false + // Act + await quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers, mockSpan, true) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).not.toHaveBeenCalled() + expect(axios.request.mock.calls[0][0].headers).not.toHaveProperty('fspiop-signature') + expect(axios.request).toBeCalledWith(expectedOptions) + jwsSignSpy.mockRestore() + }) + + it('sends the error callback NOT JWS signed', async () => { + // Arrange + const jwsSignSpy = jest.spyOn(JwsSigner.prototype, 'getSignature') + expect.assertions(5) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + mockSpan.injectContextToHttpRequest = jest.fn().mockImplementation(() => ({ + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + }, + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {} + })) + mockSpan.audit = jest.fn() + const expectedOptions = { + method: Enum.Http.RestMethods.PUT, + url: 'http://localhost:8444/payeefsp/quotes/test123/error', + data: {}, + headers: { + spanHeaders: '12345', + 'fspiop-source': 'switch', + 'fspiop-destination': 'dfsp2' + } + } + mockConfig.jws.jwsSign = false + // Act + await quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers, mockSpan, false) + // Assert + expect(mockSpan.injectContextToHttpRequest).toBeCalledTimes(1) + expect(mockSpan.audit).toBeCalledTimes(1) + expect(jwsSignSpy).not.toHaveBeenCalled() + expect(axios.request.mock.calls[0][0].headers).not.toHaveProperty('fspiop-signature') + expect(axios.request).toBeCalledWith(expectedOptions) + jwsSignSpy.mockRestore() + }) + + it('handles when the endpoint could not be found', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(undefined) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + + // Act + const action = async () => quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers, mockSpan) + + // Assert + await expect(action()).rejects.toThrow('No FSPIOP_CALLBACK_URL_QUOTES found for payeefsp unable to make error callback') + expect(axios.request).not.toHaveBeenCalled() + }) + + it('handles a http exception', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + axios.request.mockImplementationOnce(() => { throw new Error('HTTP test error') }) + + // Act + const action = async () => quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers) + + // Assert + await expect(action()).rejects.toThrow('network error in sendErrorCallback: HTTP test error') + expect(axios.request).toHaveBeenCalledTimes(1) + }) + + it('handles a http bad status code', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getParticipantEndpoint.mockReturnValueOnce(mockData.endpoints.payeefsp) + Util.generateRequestHeaders.mockReturnValueOnce({}) + const error = new Error('Test Error') + const fspiopError = ErrorHandler.ReformatFSPIOPError(error) + axios.request.mockReturnValueOnce({ + status: Enum.Http.ReturnCodes.BADREQUEST.CODE + }) + + // Act + const action = async () => quotesModel.sendErrorCallback('payeefsp', fspiopError, mockData.quoteId, mockData.headers) + + // Assert + await expect(action()).rejects.toThrow('Got non-success response sending error callback') + expect(axios.request).toHaveBeenCalledTimes(1) + }) + }) + + describe('checkDuplicateQuoteRequest', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.checkDuplicateQuoteRequest.mockRestore() + Util.calculateRequestHash.mockRestore() + }) + + it('handles a non-duplicate request', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteDuplicateCheck.mockReturnValueOnce(undefined) + const expected = { + isResend: false, + isDuplicateId: false + } + + // Act + const result = await quotesModel.checkDuplicateQuoteRequest(mockData.quoteRequest) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles a duplicate id', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteDuplicateCheck.mockReturnValueOnce({ + hash: 'this_hash_will_not_match' + }) + const expected = { + isResend: false, + isDuplicateId: true + } + + // Act + const result = await quotesModel.checkDuplicateQuoteRequest(mockData.quoteRequest) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles a matching hash', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteDuplicateCheck.mockReturnValueOnce({ + hash: Util.calculateRequestHash(mockData.quoteRequest) + }) + const expected = { + isResend: true, + isDuplicateId: true + } + + // Act + const result = await quotesModel.checkDuplicateQuoteRequest(mockData.quoteRequest) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles an exception when checking the duplicate', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteDuplicateCheck.mockImplementationOnce(() => { throw new Error('Duplicate check error') }) + + // Act + const action = async () => quotesModel.checkDuplicateQuoteRequest(mockData.quoteRequest) + + // Assert + await expect(action()).rejects.toThrow('Duplicate check error') + expect(quotesModel.db.getQuoteDuplicateCheck).toHaveBeenCalledTimes(1) + }) + }) + + describe('checkDuplicateQuoteResponse', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.checkDuplicateQuoteResponse.mockRestore() + Util.calculateRequestHash.mockRestore() + }) + + it('handles a non-duplicate request', async () => { + // Arrange + // expect.assertions(2) + quotesModel.db.getQuoteResponseDuplicateCheck.mockReturnValueOnce(undefined) + const expected = { + isResend: false, + isDuplicateId: false + } + + // Act + const result = await quotesModel.checkDuplicateQuoteResponse(mockData.quoteId, mockData.quoteResponse) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteResponseDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles a duplicate id', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteResponseDuplicateCheck.mockReturnValueOnce({ + hash: 'this_hash_will_not_match' + }) + const expected = { + isResend: false, + isDuplicateId: true } + + // Act + const result = await quotesModel.checkDuplicateQuoteResponse(mockData.quoteId, mockData.quoteResponse) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteResponseDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles a matching hash', async () => { + // Arrange + expect.assertions(2) + quotesModel.db.getQuoteResponseDuplicateCheck.mockReturnValueOnce({ + hash: Util.calculateRequestHash(mockData.quoteResponse) + }) + const expected = { + isResend: true, + isDuplicateId: true + } + + // Act + const result = await quotesModel.checkDuplicateQuoteResponse(mockData.quoteId, mockData.quoteResponse) + + // Assert + expect(result).toEqual(expected) + expect(quotesModel.db.getQuoteResponseDuplicateCheck).toHaveBeenCalledTimes(1) + }) + + it('handles an exception when checking the duplicate', async () => { + // Arrange + // expect.assertions(2) + quotesModel.db.getQuoteResponseDuplicateCheck.mockImplementationOnce(() => { throw new Error('Duplicate check error') }) + + // Act + const action = async () => quotesModel.checkDuplicateQuoteResponse(mockData.quoteId, mockData.quoteResponse) + + // Assert + await expect(action()).rejects.toThrow('Duplicate check error') + expect(quotesModel.db.getQuoteResponseDuplicateCheck).toHaveBeenCalledTimes(1) + }) + }) + + describe('writeLog', () => { + beforeEach(() => { + // restore the current method in test to its original implementation + quotesModel.writeLog.mockRestore() + }) + + it('writes to the log', () => { + // Arrange + // Act + quotesModel.writeLog('test message') + + // Assert + expect(Logger.info).toBeCalledTimes(1) }) }) }) diff --git a/test/unit/model/rules.test.js b/test/unit/model/rules.test.js index 86a78540..a03d2029 100644 --- a/test/unit/model/rules.test.js +++ b/test/unit/model/rules.test.js @@ -1,242 +1,343 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. -const RulesEngine = require(`${__SRC__}/model/rules`) + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali -test('Test rules engine jsonpath and notDeepEqual operator', async () => { - const conditions = { - any: [{ - fact: 'json-path', + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Vassilis Barzokas + -------------- + ******/ + +// jest has a buggy system for mocking dependencies that can be overcome by mocking and then +// requiring the module like below. +// more info on https://github.com/facebook/jest/issues/2582#issuecomment-321607875 +const mockRules = [ + { + conditions: { + all: [ + { + fact: 'payload', + path: '$.extensionList[?(@.key == "KYCPayerTier")].value', + operator: 'equal', + value: '1' + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == "SETTLEMENT")].currency' + } + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', params: { - fact: 'payload', - path: '$.payload.payer.partyIdInfo.fspId' - }, - operator: 'notDeepEqual', - value: ['payerfsp'] - }] - } - const event = { - type: RulesEngine.events.INVALID_QUOTE_REQUEST - } - const testFacts = { - payload: { - payer: { - partyIdInfo: { - fspId: 'payeefsp' + rerouteToFsp: 'DFSPEUR' + } + } + }, + { + conditions: { + all: [ + { + fact: 'payload', + path: '$.extensionList[?(@.key == "KYCPayerTier")].value', + operator: 'notEqual', + value: '1' + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == "SETTLEMENT")].currency' + } } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_UNSUPPORTED_CURRENCY', + message: 'The requested payee does not support the payment currency' } } } - const { events } = await RulesEngine.run([{ conditions, event }], testFacts) - expect(events).toEqual([event]) -}) +] -test('Test rules engine jsonpath fact-fact comparison', async () => { - const conditions = { - any: [{ - fact: 'json-path', - params: { - fact: 'payload', - path: '$.payload.payer.partyIdInfo.fspId' - }, - operator: 'notDeepEqual', - value: { - fact: 'json-path', - params: { - path: '$.headers[\'fspiop-source\']', - fact: 'headers' +const RulesEngine = require('../../../src/model/rules') + +describe('RulesEngine', () => { + describe('run', () => { + it('returns the expected events when using jsonpath and notDeepEqual operator', async () => { + const conditions = { + any: [{ + fact: 'payload', + path: '$.payer.partyIdInfo.fspId', + operator: 'notDeepEqual', + value: ['payerfsp'] + }] + } + const event = { + type: RulesEngine.events.INVALID_QUOTE_REQUEST + } + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + } } } - }] - } - const event = { - type: RulesEngine.events.INVALID_QUOTE_REQUEST - } - const testFacts = { - payload: { - payer: { - partyIdInfo: { - fspId: 'payeefsp' + const { events } = await RulesEngine.run([{ conditions, event }], testFacts) + expect(events).toEqual([event]) + }) + + it('returns the expected events when using jsonpath and deepEqual operator', async () => { + const conditions = { + any: [{ + fact: 'payload', + path: '$.payer.partyIdInfo.fspId', + operator: 'deepEqual', + value: 'payerfsp' + }] + } + const event = { + type: RulesEngine.events.INVALID_QUOTE_REQUEST + } + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + } } } - }, - headers: { - 'fspiop-source': 'payerfsp' - } - } - const { events } = await RulesEngine.run([{ conditions, event }], testFacts) - expect(events).toEqual([event]) -}) + const { events } = await RulesEngine.run([{ conditions, event }], testFacts) + expect(events).toEqual([event]) + }) -test('Test rules engine jsonpath array filter', async () => { - const conditions = { - any: [{ - fact: 'json-path', - params: { - fact: 'payload', - path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' - }, - operator: 'notDeepEqual', - value: ['1'] - }] - } - const event = { - type: RulesEngine.events.INVALID_QUOTE_REQUEST - } - const testFacts = { - payload: { - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '2' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run([{ conditions, event }], testFacts) - expect(events).toEqual([event]) -}) + it('returns the expected events when using jsonpath fact-fact comparison', async () => { + const conditions = { + any: [{ + fact: 'payload', + path: '$.payer.partyIdInfo.fspId', + operator: 'notDeepEqual', + value: { + path: '$.[\'fspiop-source\']', + fact: 'headers' + } + }] + } + const event = { + type: RulesEngine.events.INVALID_QUOTE_REQUEST + } + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + } + }, + headers: { + 'fspiop-source': 'payerfsp' + } + } + const { events } = await RulesEngine.run([{ conditions, event }], testFacts) + expect(events).toEqual([event]) + }) -test('Test rules engine deepEqual operator', async () => { - const conditions = { - any: [{ - fact: 'json-path', - params: { - fact: 'payload', - path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' - }, - operator: 'deepEqual', - value: ['1'] - }] - } - const event = { - type: RulesEngine.events.INVALID_QUOTE_REQUEST - } - const testFacts = { - payload: { - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '1' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run([{ conditions, event }], testFacts) - expect(events).toEqual([event]) -}) + it('returns the expected events when using jsonpath array filter', async () => { + const conditions = { + any: [{ + fact: 'payload', + path: '$.extensionList[?(@.key === \'KYCPayerTier\')].value', + operator: 'notDeepEqual', + value: ['1'] + }] + } + const event = { + type: RulesEngine.events.INVALID_QUOTE_REQUEST + } + const testFacts = { + payload: { + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '2' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run([{ conditions, event }], testFacts) + expect(events).toEqual([event]) + }) -test('Test rules engine example config INTERCEPT_QUOTE event', async () => { - const rules = require(`${__ROOT__}/config/rules.example.json`) - const testFacts = { - payee: { - accounts: [{ - ledgerAccountType: 'SETTLEMENT', - currency: 'ZAR' - }] - }, - payload: { - amount: { - currency: 'XOF' - }, - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '1' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run(rules, testFacts) - expect(events).toEqual([rules[0].event]) -}) + it('returns the expected events when using deepEqual operator', async () => { + const conditions = { + any: [{ + fact: 'payload', + path: '$.extensionList[?(@.key === \'KYCPayerTier\')].value', + operator: 'equal', + value: '1' + }] + } + const event = { + type: RulesEngine.events.INVALID_QUOTE_REQUEST + } + const testFacts = { + payload: { + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '1' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run([{ conditions, event }], testFacts) + expect(events).toEqual([event]) + }) -test('Test rules engine example config INTERCEPT_QUOTE event negative case', async () => { - const rules = require(`${__ROOT__}/config/rules.example.json`) - const testFacts = { - payee: { - accounts: [{ - ledgerAccountType: 'SETTLEMENT', - currency: 'XOF' - }] - }, - payload: { - amount: { - currency: 'XOF' - }, - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '1' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run(rules, testFacts) - expect(events).toEqual([]) -}) + it('returns the expected events when using example config for event INTERCEPT_QUOTE', async () => { + const testFacts = { + payee: { + accounts: [{ + ledgerAccountType: 'SETTLEMENT', + currency: 'ZAR' + }] + }, + payload: { + amount: { + currency: 'XOF' + }, + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '1' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run(mockRules, testFacts) + expect(events).toEqual([mockRules[0].event]) + }) -test('Test rules engine example config INVALID_QUOTE_REQUEST triggered by missing extension value', async () => { - const rules = require(`${__ROOT__}/config/rules.example.json`) - const testFacts = { - payee: { - accounts: [{ - ledgerAccountType: 'SETTLEMENT', - currency: 'ZAR' - }] - }, - payload: { - amount: { - currency: 'XOF' - }, - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run(rules, testFacts) - expect(events).toEqual([rules[1].event]) -}) + it('returns an empty array of events when using example config for INTERCEPT_QUOTE negative case', async () => { + const testFacts = { + payee: { + accounts: [{ + ledgerAccountType: 'SETTLEMENT', + currency: 'XOF' + }] + }, + payload: { + amount: { + currency: 'XOF' + }, + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '1' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run(mockRules, testFacts) + expect(events).toEqual([]) + }) -test('Test rules engine example config INVALID_QUOTE_REQUEST triggered by incorrect extension value', async () => { - const rules = require(`${__ROOT__}/config/rules.example.json`) - const testFacts = { - payee: { - accounts: [{ - ledgerAccountType: 'SETTLEMENT', - currency: 'ZAR' - }] - }, - payload: { - amount: { - currency: 'XOF' - }, - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '2' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run(rules, testFacts) - expect(events).toEqual([rules[1].event]) -}) + it('returns the expected events when using example config for INVALID_QUOTE_REQUEST triggered by missing extension value', async () => { + const testFacts = { + payee: { + accounts: [{ + ledgerAccountType: 'SETTLEMENT', + currency: 'ZAR' + }] + }, + payload: { + amount: { + currency: 'XOF' + }, + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run(mockRules, testFacts) + expect(events).toEqual([mockRules[1].event]) + }) -test('Test rules engine example config INVALID_QUOTE_REQUEST event negative case', async () => { - const rules = require(`${__ROOT__}/config/rules.example.json`) - const testFacts = { - payee: { - accounts: [{ - ledgerAccountType: 'SETTLEMENT', - currency: 'XOF' - }] - }, - payload: { - amount: { - currency: 'XOF' - }, - extensionList: [ - { key: 'blah', value: 'whatever' }, - { key: 'KYCPayerTier', value: '2' }, - { key: 'noise', value: 'blah' } - ] - } - } - const { events } = await RulesEngine.run(rules, testFacts) - expect(events).toEqual([]) + it('returns the expected events when using example config INVALID_QUOTE_REQUEST triggered by incorrect extension value', async () => { + const testFacts = { + payee: { + accounts: [{ + ledgerAccountType: 'SETTLEMENT', + currency: 'ZAR' + }] + }, + payload: { + amount: { + currency: 'XOF' + }, + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '2' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run(mockRules, testFacts) + expect(events).toEqual([mockRules[1].event]) + }) + + it('returns the expected events when using example config INVALID_QUOTE_REQUEST event negative case', async () => { + const testFacts = { + payee: { + accounts: [{ + ledgerAccountType: 'SETTLEMENT', + currency: 'XOF' + }] + }, + payload: { + amount: { + currency: 'XOF' + }, + extensionList: [ + { key: 'blah', value: 'whatever' }, + { key: 'KYCPayerTier', value: '2' }, + { key: 'noise', value: 'blah' } + ] + } + } + const { events } = await RulesEngine.run(mockRules, testFacts) + expect(events).toEqual([]) + }) + }) }) diff --git a/test/unit/rules/fx.test.js b/test/unit/rules/fx.test.js new file mode 100644 index 00000000..e4c4a916 --- /dev/null +++ b/test/unit/rules/fx.test.js @@ -0,0 +1,714 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Vassilis Barzokas + -------------- + ******/ + +const RulesEngine = require('../../../src/model/rules') + +const fxRules = { + EURtoXOFSendEUR: { // EUR to XOF, amountType=SEND, amount.currency=EUR + conditions: { + all: [ + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' + ] + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'EUR' + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR', + sourceCurrency: 'EUR', + rerouteToFspCurrency: 'XOF', + additionalHeaders: { + 'x-fspiop-sourcecurrency': 'EUR', + 'x-fspiop-destinationcurrency': 'XOF' + } + } + } + }, + EURtoXOFReceiveXOF: { // EUR to XOF, amountType=RECEIVE, amount.currency=XOF + conditions: { + all: [ + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' + ] + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'XOF' + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR', + sourceCurrency: 'EUR', + rerouteToFspCurrency: 'XOF', + additionalHeaders: { + 'x-fspiop-sourcecurrency': 'EUR', + 'x-fspiop-destinationcurrency': 'XOF' + } + } + } + }, + XOFtoEURSendXOF: { // XOF to EUR, amountType=SEND, amount.currency=XOF + conditions: { + all: [ + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' + ] + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'XOF' + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPXOF', + sourceCurrency: 'XOF', + rerouteToFspCurrency: 'EUR', + additionalHeaders: { + 'x-fspiop-sourcecurrency': 'XOF', + 'x-fspiop-destinationcurrency': 'EUR' + } + } + } + }, + XOFtoEURReceiveEUR: { // XOF to EUR, amountType=RECEIVE, amount.currency=EUR + conditions: { + all: [ + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' + ] + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'EUR' + } + ] + }, + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPXOF', + sourceCurrency: 'XOF', + rerouteToFspCurrency: 'EUR', + additionalHeaders: { + 'x-fspiop-sourcecurrency': 'XOF', + 'x-fspiop-destinationcurrency': 'EUR' + } + } + } + }, + payerUnsupportedCurrency: { // PAYER_UNSUPPORTED_CURRENCY + conditions: { + all: [ + { + fact: 'payload', + path: '$.amountType', + operator: 'equal', + value: 'SEND' + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYER_UNSUPPORTED_CURRENCY', + message: 'Requested currency not available for payer. Transfer not allowed.' + } + } + }, + payeeUnsupportedCurrency: { // PAYEE_UNSUPPORTED_CURRENCY + conditions: { + all: [ + { + fact: 'payload', + path: '$.amountType', + operator: 'equal', + value: 'RECEIVE' + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_UNSUPPORTED_CURRENCY', + message: 'Requested currency not available for payee. Transfer not allowed.' + } + } + }, + FSPIOPSourceDoesNotMatchPayer: { // FSPIOP-Source not matching Payer + conditions: { + all: [ + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' + ] + }, + { + fact: 'headers', + path: '$.fspiop-source', + operator: 'notEqual', + value: { + fact: 'payload', + path: '$.payer.partyIdInfo.fspId' + } + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYER_FSPIO', + message: 'The payer FSP does not match the fspiop-source header' + } + } + }, + firstNameMissing: { // First Name is missing from the quote request + conditions: { + all: [ + { + any: [ + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + } + ] + }, + { + fact: 'payload', + path: '$.payer.personalInfo.complexName.firstName', + operator: 'isString', + value: false + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'MISSING_ELEMENT', + message: 'child \'Party\' fails because [child \'PartyPersonalInfo\' fails because [child \'PartyComplexName\' fails because [child \'firstName\' fails because [\'firstName\' is required]]]]' + } + } + }, + payerHasMoreThanOneCurrency: { // Payer has more than one currency + conditions: { + all: [ + { + any: [ + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + } + ] + }, + { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)]', + operator: 'isArray', + value: true + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYER_ERROR', + message: 'Payer FSP has more than 1 active currency account. Switch does not support more than 1 active currency account for Forex Requests' + } + } + }, + payeeHasMoreThanOneCurrency: { // Payee has more than one currency + conditions: { + all: [ + { + any: [ + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + }, + { + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)].currency' + } + } + ] + }, + { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'POSITION\' && @.isActive == 1)]', + operator: 'isArray', + value: true + } + ] + }, + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_ERROR', + message: 'Payee FSP has more than 1 active currency account. Switch does not support more than 1 active currency account for Forex Requests' + } + } + } +} + +describe('Forex rules', () => { + describe('EURtoXOFSendEUR', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'XYZ' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.EURtoXOFSendEUR], testFacts) + expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]) + }) + }) + describe('EURtoXOFReceiveXOF', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.EURtoXOFReceiveXOF], testFacts) + expect(events).toEqual([fxRules.EURtoXOFReceiveXOF.event]) + }) + }) + describe('XOFtoEURSendXOF', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'EUR' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.XOFtoEURSendXOF], testFacts) + expect(events).toEqual([fxRules.XOFtoEURSendXOF.event]) + }) + }) + describe('XOFtoEURReceiveEUR', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.XOFtoEURReceiveEUR], testFacts) + expect(events).toEqual([fxRules.XOFtoEURReceiveEUR.event]) + }) + }) + describe('payerUnsupportedCurrency', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'SEND', + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.payerUnsupportedCurrency], testFacts) + expect(events).toEqual([fxRules.payerUnsupportedCurrency.event]) + }) + }) + describe('payeeUnsupportedCurrency', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.payeeUnsupportedCurrency], testFacts) + expect(events).toEqual([fxRules.payeeUnsupportedCurrency.event]) + }) + }) + describe('FSPIOPSourceDoesNotMatchPayer', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.FSPIOPSourceDoesNotMatchPayer], testFacts) + expect(events).toEqual([fxRules.FSPIOPSourceDoesNotMatchPayer.event]) + }) + }) + describe('firstNameMissing', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + personalInfo: { + complexName: { + lastName: 'Hagman' + }, + dateOfBirth: '1983-10-25' + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'EUR' } + ] + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'XOF' } + ] + } + + } + const { events } = await RulesEngine.run([fxRules.firstNameMissing], testFacts) + expect(events).toEqual([fxRules.firstNameMissing.event]) + }) + }) + describe('payerHasMoreThanOneCurrency', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'EUR' }, + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'USD' } + ] + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'XOF' } + ] + } + + } + const { events } = await RulesEngine.run([fxRules.payerHasMoreThanOneCurrency], testFacts) + expect(events).toEqual([fxRules.payerHasMoreThanOneCurrency.event]) + }) + }) + describe('payeeHasMoreThanOneCurrency', () => { + it('raises INVALID_QUOTE_REQUEST', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payer: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'EUR' } + ] + }, + payee: { + accounts: [ + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'XOF' }, + { isActive: 1, ledgerAccountType: 'POSITION', currency: 'USD' } + ] + } + + } + const { events } = await RulesEngine.run([fxRules.payeeHasMoreThanOneCurrency], testFacts) + expect(events).toEqual([fxRules.payeeHasMoreThanOneCurrency.event]) + }) + }) +}) diff --git a/test/unit/server.test.js b/test/unit/server.test.js new file mode 100644 index 00000000..2b59c243 --- /dev/null +++ b/test/unit/server.test.js @@ -0,0 +1,119 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * Crosslake + - Lewis Daly + -------------- + ******/ + +let Hapi +let Logger +let Database + +describe('Server', () => { + beforeEach(() => { + jest.resetModules() + + jest.mock('@hapi/hapi') + jest.mock('@mojaloop/central-services-logger') + jest.mock('../../src/data/cachedDatabase') + + Hapi = require('@hapi/hapi') + Logger = require('@mojaloop/central-services-logger') + Database = require('../../src/data/cachedDatabase') + }) + + it('runs the server', async () => { + // Arrange + Database.mockImplementationOnce(() => ({ + connect: jest.fn().mockResolvedValueOnce() + })) + const mockRegister = jest.fn() + const mockStart = jest.fn() + const mockRoute = jest.fn() + const mockLog = jest.fn() + Hapi.Server.mockImplementationOnce(() => ({ + app: { + database: null + }, + register: mockRegister, + start: mockStart, + route: mockRoute, + log: mockLog, + info: { + host: 'localhost', + port: 3333, + uri: 'http://localhost:3333' + } + })) + + // Act + const server = require('../../src/server') + await server() + + // Assert + expect(mockRegister).toHaveBeenCalledTimes(4) + expect(mockStart).toHaveBeenCalledTimes(1) + expect(mockRoute).toHaveBeenCalledTimes(1) + expect(mockLog).toHaveBeenCalledTimes(1) + }) + + it('handles exception when starting', async () => { + // Arrange + Database.mockImplementationOnce(() => ({ + connect: jest.fn().mockResolvedValueOnce() + })) + const mockRegister = jest.fn().mockImplementationOnce(() => { throw new Error('Test Error') }) + const mockStart = jest.fn() + const mockRoute = jest.fn() + const mockLog = jest.fn() + Hapi.Server.mockImplementationOnce(() => ({ + app: { + database: null + }, + register: mockRegister, + route: mockRoute, + start: mockStart, + log: mockLog, + info: { + host: 'localhost', + port: 3333, + uri: 'http://localhost:3333' + } + })) + + // Act + const server = require('../../src/server') + await server() + + // Assert + expect(mockRegister).toHaveBeenCalledTimes(1) + expect(mockStart).not.toHaveBeenCalled() + expect(mockRoute).not.toHaveBeenCalled() + expect(mockLog).not.toHaveBeenCalled() + expect(Logger.error).toHaveBeenCalledTimes(1) + }) +}) diff --git a/test/unit/serverStart.test.js b/test/unit/serverStart.test.js new file mode 100644 index 00000000..44405cf1 --- /dev/null +++ b/test/unit/serverStart.test.js @@ -0,0 +1,170 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files 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, the Mojaloop files are 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. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Rajiv Mothilal + -------------- + ******/ + +const { mockRequest: Mockgen, defaultHeaders } = require('../util/helper') +const Server = require('../../src/server') +jest.mock('../../src/model/quotes') +const QuotesModel = require('../../src/model/quotes') +let Database +let server + +jest.setTimeout(10000) + +describe('Server Start', () => { + beforeEach(() => { + jest.resetModules() + jest.mock('../../src/data/cachedDatabase') + Database = require('../../src/data/cachedDatabase') + }) + + afterEach(() => { + server.stop() + }) + + it('runs the server', async () => { + // Arrange + Database.mockImplementationOnce(() => ({ + connect: jest.fn().mockResolvedValueOnce() + })) + + // Act + server = await Server() + const requests = Mockgen().requestsAsync('/health', 'get') + // Arrange + const mock = await requests + const options = { + method: 'get', + url: '' + mock.request.path, + headers: { + ...mock.request.headers + } + } + + // Act + try { + const response = await server.inject(options) + expect(response.statusCode).toBe(200) + jest.setTimeout(5000) + } catch (error) { + console.log(error) + } + }) + + it('post /quotes throws error when missing mandatory header', async () => { + // Arrange + Database.mockImplementationOnce(() => ({ + connect: jest.fn().mockResolvedValueOnce() + })) + + // Act + server = await Server() + const requests = Mockgen().requestsAsync('/quotes', 'post') + const mock = await requests + + // Arrange + const headers = defaultHeaders() + delete headers['fspiop-destination'] + const expectedResult = { + errorInformation: { + errorCode: '3102', + errorDescription: 'Missing mandatory element - /header must have required property \'fspiop-destination\'' + } + } + mock.request.body.payee.personalInfo.complexName = { + firstName: 'firstName payee', + middleName: 'middleName payee', + lastName: 'lastName payee' + } + mock.request.body.payer.personalInfo.complexName = { + firstName: 'firstName payer', + middleName: 'middleName payer', + lastName: 'lastName payer' + } + + const options = { + method: 'post', + url: '' + mock.request.path, + headers, + payload: mock.request.body + } + // Act + try { + const response = await server.inject(options) + expect(response.statusCode).toBe(400) + expect(response.result).toEqual(expectedResult) + } catch (error) { + console.log(error) + } + }) + + it('post /quotes with additional asian (Myanmar) unicode characters', async () => { + // Arrange + Database.mockImplementationOnce(() => ({ + connect: jest.fn().mockResolvedValueOnce() + })) + + QuotesModel.mockImplementationOnce(() => ({ + handleQuoteRequest: jest.fn().mockResolvedValueOnce() + })) + // Act + server = await Server() + const mock = await Mockgen().requestsAsync('/quotes', 'post') + + mock.request.body.payee.personalInfo.complexName = { + firstName: 'firstName payee', + middleName: 'middleName payee', + lastName: 'lastName payee' + } + mock.request.body.payer.personalInfo.complexName = { + firstName: 'firstName payer', + middleName: 'ကောင်းထက်စံ', // Myanmar unicode characters + lastName: 'lastName payer' + } + + // Arrange + const headers = defaultHeaders() + + const options = { + method: 'post', + url: '' + mock.request.path, + headers, + payload: mock.request.body + } + + // Act + try { + const response = await server.inject(options) + expect(response.statusCode).toBe(202) + } catch (error) { + console.log(error) + } + }) +}) diff --git a/test/util/helper.js b/test/util/helper.js index 90ca90ab..fca8fb2c 100644 --- a/test/util/helper.js +++ b/test/util/helper.js @@ -23,6 +23,39 @@ ******/ 'use strict' +const SwagMock = require('swagmock') +const Path = require('path') +const apiPath = Path.resolve(__dirname, '../../src/interface/swagger.json') +let mockGen + +/** + * @object baseMockRequest + * + * @description A basic mock request object for passing into handlers + * + */ +const baseMockRequest = { + headers: { + 'fspiop-source': 'payerfsp' + }, + info: { + id: '12345' + }, + params: { + id: 'quoteId12345' + }, + server: { + app: { + database: jest.fn() + }, + log: jest.fn() + }, + span: { + setTags: jest.fn(), + audit: jest.fn() + } +} + /** * @function defaultHeaders * @@ -48,6 +81,33 @@ function defaultHeaders () { } } +/** + * Global MockGenerator Singleron + */ +const mockRequest = () => { + if (mockGen) { + return mockGen + } + + mockGen = SwagMock(apiPath) + + /** + * Add an async version of requests + */ + mockGen.requestsAsync = async (path, operation) => { + return new Promise((resolve, reject) => { + mockGen.requests( + { path, operation }, + (error, mock) => error ? reject(error) : resolve(mock) + ) + }) + } + + return mockGen +} + module.exports = { - defaultHeaders + baseMockRequest, + defaultHeaders, + mockRequest }