diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..2da2da15 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# fdc3-maintainers will be default reviewers for everything in the repo unless a later match takes precedence +* @finos/fdc3-maintainers + +# Any changes to this CODEOWNERS file should be reviewed by finos-admins +/.github/CODEOWNERS @finos/finos-admins diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 298f435b..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributing to {project name} - -{project name} is [Apache 2.0 licensed](LICENSE) and accepts contributions via git pull requests. Each commit must include a DCO line in the git commit message: - -`Signed-off-by: GitHub User Name ` - -This sign-off means you agree the commit satisfies the -[Developer Certificate of Origin (DCO).](https://developercertificate.org/) - -## Contributing Issues - -### Prerequisites - -* [ ] Have you [searched for duplicates](https://github.com/finos-labs/{project name}/issues?utf8=%E2%9C%93&q=)? A simple search for exception error messages or a summary of the unexpected behaviour should suffice. -* [ ] Are you running the latest version? -* [ ] Are you sure this is a bug or missing capability? - -### Raising an Issue -* Create your issue [here](https://github.com/finos-labs/{project name}/issues/new). -* New issues contain two templates in the description: bug report and enhancement request. Please pick the most appropriate for your issue, **then delete the other**. - * Please also tag the new issue with either "Bug" or "Enhancement". -* Please use [Markdown formatting](https://help.github.com/categories/writing-on-github/) -liberally to assist in readability. - * [Code fences](https://help.github.com/articles/creating-and-highlighting-code-blocks/) for exception stack traces and log entries, for example, massively improve readability. - -## Contributing Pull Requests (Code & Docs) -To make review of PRs easier, please: - - * Please make sure your PRs will merge cleanly - PRs that don't are unlikely to be accepted. - * For code contributions, follow the existing code layout. - * For documentation contributions, follow the general structure, language, and tone of the [existing docs](https://github.com/finos-labs/{project name}/wiki). - * Keep commits small and cohesive - if you have multiple contributions, please submit them as independent commits (and ideally as independent PRs too). - * Reference issues if your PR has anything to do with an issue (even if it doesn't address it). - * Minimise non-functional changes (e.g. whitespace). - * Ensure all new files include a header comment block containing the [Apache License v2.0 and your copyright information](http://www.apache.org/licenses/LICENSE-2.0#apply). - * If necessary (e.g. due to 3rd party dependency licensing requirements), update the [NOTICE file](https://github.com/finos/{project name}/blob/master/NOTICE) with any new attribution or other notices - - -### Commit and PR Messages - -* **Reference issues, wiki pages, and pull requests liberally!** -* Use the present tense ("Add feature" not "Added feature") -* Use the imperative mood ("Move button left..." not "Moves button left...") -* Limit the first line to 72 characters or less diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index e6e4bd12..00000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: 🐛 Bug Report -about: If something isn't working as expected 🤔 - ---- - -## Bug Report - -### Steps to Reproduce: - 1. ...step 1 description... - 2. ...step 2 description... - 3. ...step 3 description... - -### Expected Result: -...description of what you expected to see... - -### Actual Result: -...what actually happened, including full exceptions (please include the entire stack trace, including "caused by" entries), log entries, screen shots etc. where appropriate... - -### Environment: -...version and build of the project, OS and runtime versions, virtualised environment (if any), etc. ... - -### Additional Context: -...add any other context about the problem here. If applicable, add screenshots to help explain... diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index ba396f76..00000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: 🚀 Feature Request -about: I have a suggestion (and may want to implement it 🙂) - ---- - -## Feature Request - -### Description of Problem: -...what *problem* are you trying to solve that the project doesn't currently solve? - -...please resist the temptation to describe your request in terms of a solution. Job Story form ("When [triggering condition], I want to [motivation/goal], so I can [outcome].") can help ensure you're expressing a problem statement. - -### Potential Solutions: -...clearly and concisely describe what you want to happen. Add any considered drawbacks. - -... if you've considered alternatives, clearly and concisely describe those too. diff --git a/.github/ISSUE_TEMPLATE/Support_question.md b/.github/ISSUE_TEMPLATE/Support_question.md deleted file mode 100644 index c6c4deb3..00000000 --- a/.github/ISSUE_TEMPLATE/Support_question.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 🤗 Support Question -about: If you have a question about configuration, usage, etc. 💬 - ---- - -## Support Question - -...ask your question here. - -...be sure to search existing issues since someone might have already asked something similar. diff --git a/.github/ISSUE_TEMPLATE/Vote.md b/.github/ISSUE_TEMPLATE/Vote.md new file mode 100644 index 00000000..d1a81d79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Vote.md @@ -0,0 +1,30 @@ +--- +name: "[VOTE]" +about: Vote on a project matter +title: "[VOTE] " +labels: vote +--- + +## Vote Description + + + +## Binding Voters + + + +## Vote + +Please react to this issue: + +- 👍 Approve +- 👎 Deny +- 👀 Abstain + +## Result + + + +- Total votes: +- Binding votes (Approve, Deny, Abstained): +- Result: diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..d4434402 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,55 @@ +name: 🐛 Bug Report +description: If something isn't working as expected 🤔 +title: "[Bug] " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug! Please fill out the form below. + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Please provide clear steps to reproduce the issue + placeholder: | + 1. Step 1 description + 2. Step 2 description + 3. Step 3 description + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Result + description: What did you expect to happen? + placeholder: Description of what you expected to see... + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual Result + description: What actually happened? Include full exceptions (entire stack trace, including "caused by" entries), log entries, screenshots, etc. + placeholder: What actually happened... + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: Version and build of the project, OS and runtime versions, virtualised environment (if any), etc. + placeholder: | + - Project version: + - OS: + - Java version: + - Desktop Agent: + - Other relevant details: + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any other context about the problem here. If applicable, add screenshots to help explain. + placeholder: Any additional information that might be helpful... diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..1350fac0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,36 @@ +name: 🚀 Feature Request +description: I have a suggestion (and may want to implement it 🙂)! +title: "[Feature] " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Please resist the temptation to describe your request in terms of a solution. Job Story form ("When [triggering condition], I want to [motivation/goal], so I can [outcome].") can help ensure you're expressing a problem statement. + - type: textarea + id: problem + attributes: + label: Description of Problem + description: What *problem* are you trying to solve that the project doesn't currently solve? + placeholder: | + When [triggering condition], I want to [motivation/goal], so I can [outcome]. + + Describe the problem clearly... + validations: + required: true + - type: textarea + id: solutions + attributes: + label: Potential Solutions + description: Clearly and concisely describe what you want to happen. Add any considered drawbacks. If you've considered alternatives, clearly and concisely describe those too. + placeholder: | + Proposed solution: + - Description + - Benefits + - Drawbacks + + Alternatives considered: + - Alternative 1 + - Alternative 2 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/support_question.yml b/.github/ISSUE_TEMPLATE/support_question.yml new file mode 100644 index 00000000..d5d4e7c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support_question.yml @@ -0,0 +1,17 @@ +name: 🤗 Support Question +description: If you have a question about configuration, usage, etc. 💬 +title: "[Support] " +labels: ["question", "support"] +body: + - type: markdown + attributes: + value: | + Please search existing issues since someone might have already asked something similar. + - type: textarea + id: question + attributes: + label: Support Question + description: Ask your question here. Be as specific as possible. + placeholder: What would you like to know? + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..cfbd879b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +version: 2 + +updates: + # Maven dependencies + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + commit-message: + prefix: "chore(deps)" + include: "scope" + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions-minor-and-patch: + update-types: + - "minor" + - "patch" + open-pull-requests-limit: 10 + commit-message: + prefix: "ci(deps)" + include: "scope" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..a5f2bb03 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Describe your change + + + +### Related Issue + + + + + +## Contributor License Agreement + + + +- [ ] I acknowledge that a contributor license agreement is required and that I have one in place or will seek to put one in place ASAP. + +## Review Checklist + +- [ ] **Issue**: Is an issue linked above (if applicable)? +- [ ] **Build**: Does `mvn clean install` pass locally? +- [ ] **License**: Do new source files include the Apache 2.0 license header? +- [ ] **NOTICE**: If new third-party dependencies were added, is [NOTICE](../NOTICE) updated? diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..83d48557 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,53 @@ +name: Static code analysis + +on: + push: + branches: [main] + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + schedule: + # Run every day at 5am and 5pm UTC + - cron: "0 5,17 * * *" + +permissions: read-all + +jobs: + analyze: + name: CodeQL analysis + runs-on: ubuntu-latest + permissions: + security-events: write + + strategy: + fail-fast: false + matrix: + language: [java-kotlin, actions] + + steps: + - name: Harden runner + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up JDK 17 + if: matrix.language == 'java-kotlin' + uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 + with: + distribution: temurin + java-version: "17" + cache: maven + + - name: Initialize CodeQL + uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + if: matrix.language == 'java-kotlin' + uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 + + - name: Analyze + uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..8e7fa11f --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,55 @@ +name: Maven CI Tests and Coverage + +# Controls when the workflow will run on any branch +on: + push: + branches: + - main + pull_request: + +# Least privilege by default; the test job widens this to what it actually needs. +permissions: + contents: read + +# Define the jobs for this workflow +jobs: + test: + runs-on: ubuntu-latest + + permissions: + contents: read + id-token: write + pull-requests: write + + steps: + - name: Harden runner + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up JDK 17 + uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 + with: + distribution: temurin + java-version: "17" + cache: maven + + # No setup-node step: frontend-maven-plugin downloads its own pinned Node and npm into + # target/node-installation, so the build does not use a runner-provided Node at all. + + - name: Run tests with coverage + run: mvn -B clean verify + + - name: Codecov + continue-on-error: true + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + use_oidc: true + directory: . + files: | + fdc3-agent-proxy/target/site/jacoco/jacoco.xml + fdc3-get-agent/target/site/jacoco/jacoco.xml + fdc3-context/target/site/jacoco/jacoco.xml diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml new file mode 100644 index 00000000..0aa28fff --- /dev/null +++ b/.github/workflows/maven-build.yml @@ -0,0 +1,32 @@ +name: Maven build + +permissions: + contents: read + +on: + push: + branches: [main] + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Harden runner + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up JDK 17 + uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0 + with: + distribution: temurin + java-version: "17" + cache: maven + + - name: Build and test + run: mvn -B clean install diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000..a11f4e44 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,52 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + branch_protection_rule: + schedule: + # "At 17:05 on Friday" + - cron: "5 17 * * 5" + push: + branches: ["main"] + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write + + steps: + - name: Harden runner + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Run analysis + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 + with: + results_file: results.sarif + results_format: sarif + repo_token: ${{ secrets.GITHUB_TOKEN }} + publish_results: false + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: Upload to code-scanning + uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 + with: + sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index fa116c91..20adfb13 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,18 @@ docs/contributing.md # We use YARN website/package-lock.json + +# Maven target +target/ + +# The codegen manifests and their lockfiles under src/main/npm are committed deliberately, so +# that 'npm ci' installs a fixed toolchain. Only an accidental local install is ignored. +src/main/npm/node_modules/ +*/src/main/npm/node_modules/ + +# Eclipse Ignore +.classpath +.project +.settings/* +*/.settings +fdc3-java-api.code-workspace diff --git a/.github/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md similarity index 69% rename from .github/CODE_OF_CONDUCT.md rename to CODE_OF_CONDUCT.md index fc9bcda0..e5ea83b0 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ -# Code of Conduct for {project name} +# Code of Conduct for FDC3 Java API Please see the [Community Code of Conduct](https://www.finos.org/code-of-conduct). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ee24c348 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,157 @@ +# Contributing to FDC3 Java API + +This repository is part of the [FDC3 project](https://fdc3.finos.org) at FINOS. It provides a Java implementation of the [FDC3 Standard](https://fdc3.finos.org/docs/api/spec) APIs and related libraries, and is maintained alongside the main [FDC3 repository](https://github.com/finos/FDC3). + +Contributors to this repository are subject to the same FINOS contribution requirements as the broader FDC3 project. For the overall FDC3 contribution policy, issue workflows, and Working Group processes, see [Contributing to FDC3](https://github.com/finos/FDC3/blob/main/CONTRIBUTING.md). This document supplements that policy with guidance specific to this repository. + +The project is also governed by: + +* [Linux Foundation Antitrust Policy](https://www.linuxfoundation.org/antitrust-policy/) +* FINOS [IP Policy](https://community.finos.org/governance-docs/IP-policy.pdf) +* FINOS [Code of Conduct](https://community.finos.org/docs/governance/code-of-conduct) +* FINOS [Collaborative Principles](https://community.finos.org/docs/governance/collaborative-principles/) +* FINOS [Meeting Procedures](https://community.finos.org/docs/governance/meeting-procedures/) + +FDC3 Java API is [Apache 2.0 licensed](LICENSE) and accepts contributions via Git pull requests. + +## Contributor License Agreement + +_NOTE:_ Commits and pull requests to FINOS repositories will only be accepted from those participants with an active, executed Individual Contributor License Agreement (ICLA) with FINOS, _OR_ who are covered under an existing and active Corporate Contribution License Agreement (CCLA) executed with FINOS. Commits from individuals not covered under an ICLA or CCLA will be flagged and blocked by the [Linux Foundation EasyCLA tool](https://easycla.lfx.linuxfoundation.org/#/). + +*Need an ICLA? Unsure if you are covered under an existing CCLA? Email [help@finos.org](mailto:help@finos.org).* + +## Contribution Process + +Before making a contribution, please take the following steps: + +1. Check whether there's already an open issue related to your proposed contribution. If there is, join the discussion and propose your contribution there. +2. If there isn't already a relevant issue, create one describing your contribution and the problem you're trying to solve. +3. Respond to any questions or suggestions raised in the issue by other developers. +4. Fork the project repository and prepare your proposed contribution. +5. Submit a pull request. + +## Issue Lifecycle + +### Prerequisites + +* Have you [searched for duplicates](https://github.com/finos-labs/fdc3-java-api/issues)? A simple search for exception error messages or a summary of the unexpected behaviour should suffice. +* Are you using the latest version of the project? +* Are you sure this is a bug or missing capability? + +### Issue Creation + +* Create your issue [here](https://github.com/finos-labs/fdc3-java-api/issues/new). +* Choose the most appropriate issue template: bug report, feature request, or support question. +* Please use [Markdown formatting](https://help.github.com/categories/writing-on-github/) liberally to assist in readability. +* Use [code fences](https://help.github.com/articles/creating-and-highlighting-code-blocks/) for exception stack traces and log entries. + +### Discussion + +Issues that change the project usually benefit from discussion. You can post comments directly on the issue, ask for it to be added to an FDC3 meeting agenda by emailing [fdc3@finos.org](mailto:fdc3@finos.org), sending a message to the [#fdc3 channel on the FINOS Slack](https://finos-lf.slack.com/messages/fdc3/), or tag the FDC3 maintainers (`@finos/fdc3-maintainers`) in your issue, as described in [Contributing to FDC3](https://github.com/finos/FDC3/blob/main/CONTRIBUTING.md). + +Issues should be connected to the pull request that resolves them. Prefix your pull request's description with a keyword and issue number, e.g. `resolves #123`. For more details see [GitHub's documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue). + +## How to Contribute a Patch + +**1. Fork the repo** + +() + +**2. Create your feature branch** + +`git checkout -b feature/fooBar` + +**3. Commit your changes** + +`git commit -am 'Describe what you changed'` + +**4. Push to the branch** + +`git push origin feature/fooBar` + +**5. Create a Pull Request** + +For help creating a pull request from your fork, [see GitHub's documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). + +## Contribution Guidelines + +To make review of PRs easier, please: + +* Make sure your PR will merge cleanly. PRs that don't are unlikely to be accepted. +* For code contributions, follow the existing code layout and include the [Apache License v2.0 header](http://www.apache.org/licenses/LICENSE-2.0#apply) on new source files. +* Keep commits small and cohesive. If you have multiple contributions, submit them as independent commits and, ideally, as independent PRs. +* Reference issues if your PR has anything to do with an issue, even if it doesn't directly address it. +* Minimize non-functional changes, such as unnecessary whitespace changes. +* If necessary, due to third-party dependency licensing requirements, update the [NOTICE file](./NOTICE) with any new attribution or other notices. +* Run `mvn clean install` locally before submitting. + +### Commit and PR Messages + +* Reference issues, wiki pages, and pull requests liberally. +* Use the present tense ("Add feature" not "Added feature"). +* Use the imperative mood ("Move button left..." not "Moves button left..."). +* Limit the first line to 72 characters or less. + +## Governance + +Governance of the FDC3 Standard and Working Group is defined in the [FDC3 Governance document](https://github.com/finos/FDC3/blob/main/GOVERNANCE.md) and [Contributing to FDC3](https://github.com/finos/FDC3/blob/main/CONTRIBUTING.md). The sections below describe governance for this repository specifically. + +### Roles + +The project community consists of Contributors and Maintainers: + +* A **Contributor** is anyone who submits a contribution to the project. Contributions may include code, issues, comments, documentation, media, or any combination of the above. +* A **Maintainer** is a Contributor who, by virtue of their contribution history, has been given write access to project repositories and may merge approved contributions. +* The **Lead Maintainer** is the project's interface with the FINOS team and Board. They are responsible for approving [quarterly project reports](https://community.finos.org/docs/governance/#project-governing-board-reporting) and communicating on behalf of the project. The Lead Maintainer is elected by a vote of the Maintainers. + +The current Maintainer roster is listed in [MAINTAINERS.md](./MAINTAINERS.md). + +### Contribution Rules + +Anyone is welcome to submit a contribution to the project. The rules below apply to all contributions. The key words **MUST**, **SHALL**, **SHOULD**, **MAY**, etc. in this document are to be interpreted as described in [IETF RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). + +* All contributions **MUST** be submitted as pull requests, including contributions by Maintainers. +* All pull requests **SHOULD** be reviewed by a Maintainer other than the Contributor before being merged. +* Pull requests for non-trivial contributions **SHOULD** remain open for a review period sufficient to give all Maintainers an opportunity to review and comment. +* After the review period, if no Maintainer objects to the pull request, any Maintainer **MAY** merge it. +* If any Maintainer objects to a pull request, the Maintainers **SHOULD** try to reach consensus through discussion. If no consensus can be reached, any Maintainer **MAY** call for a vote on the contribution. + +### Maintainer Voting + +The Maintainers **MAY** hold votes only when they are unable to reach consensus on an issue. Any Maintainer **MAY** call a vote on a contested issue. Votes **SHALL** take the form of: + +* `+1` — agree +* `-1` — disagree +* `+0` — abstain + +Issues **SHALL** be decided by the majority of votes cast. If there is only one Maintainer, they **SHALL** decide any issue otherwise requiring a vote. + +The Maintainers **SHALL** decide the following matters by consensus or, if necessary, a vote: + +* Contested pull requests +* Election and removal of the Lead Maintainer +* Election and removal of Maintainers + +All Maintainer votes **MUST** be carried out transparently, with all discussion and voting occurring in public using one of the following methods: + +* Comments associated with the relevant issue or pull request, if applicable +* The project mailing list or another official public communication channel +* A regular, minuted project meeting + +Votes on maintainer matters may also use the [Vote issue template](.github/ISSUE_TEMPLATE/Vote.md). + +### Maintainer Qualifications + +Any Contributor who has made a substantial contribution to the project **MAY** apply or be nominated to become a Maintainer. The existing Maintainers **SHALL** decide whether to approve the nomination according to the Maintainer Voting process described above. + +### Maintainer List + +All changes to the Maintainer list are managed publicly: + +* Any addition, removal, or update **MUST** be submitted as a **pull request** to `MAINTAINERS.md`. +* If the change requires a vote, the vote outcome **MUST** be documented in or linked from the pull request description or comments. +* Whenever `MAINTAINERS.md` is updated with a change to maintainership, please email **[help@finos.org](mailto:help@finos.org)**. + +### Changes to This Document + +This document **MAY** be amended by a vote of the Maintainers according to the Maintainer Voting process above. diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000..8da06577 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,36 @@ +# Maintainers + +This file lists the maintainers of this repository. + +This repository is part of the [FDC3 project](https://fdc3.finos.org) at FINOS. Maintainers of this repository are inherited from the [FDC3 maintainers](https://github.com/finos/FDC3/blob/main/MAINTAINERS.md), following the same approach as [fdc3-dotnet](https://github.com/finos/fdc3-dotnet/blob/main/MAINTAINERS.md). + +## Current maintainers + +| GitHub Username | Name | Organization | Email | +|----------------|------|--------------|-------| +| @Roaders | *please add name* | *please add organization* | *please add email* | +| @Vivek-NatWest | *please add name* | *please add organization* | *please add email* | +| @Yannick-Malins | Yannick | @SymphonyOSF | *please add email* | +| @bingenito | Brian Ingenito | @morganstanley | *please add email* | +| @donbasuno | Johan Sandersson | *please add organization* | *please add email* | +| @hughtroeger | Hugh Troeger | FactSet Research Systems | *please add email* | +| @julianna-ciq | Julianna Langston | interop.io | *please add email* | +| @kemerava | *please add name* | *please add organization* | *please add email* | +| @kriswest | Kris West | NatWest Group | *please add email* | +| @mattjamieson | Matt Jamieson | @whitedogio | *please add email* | +| @mistryvinay | Vinay Mistry | Symphony | mrvinaymistry@gmail.com | +| @nkolba | Nicholas Kolba | *please add organization* | *please add email* | +| @novavi | Derek Novavi | S&P Global | *please add email* | +| @openfin-johans | Johan Sandersson | OpenFin | *please add email* | + +For information about maintainer responsibilities and resources, see the [FINOS Maintainers Cheatsheet](https://community.finos.org/docs/finos-maintainers-cheatsheet). + +## Updating this file + +All changes to the maintainer list are managed openly: + +- **Submit a Pull Request** to this file for any addition, removal, or update. +- **If your project's governance requires a vote**, document or link to the vote outcome in the PR description or comments. +- This process creates a public audit trail of project leadership over time. + +Please email **help@finos.org** whenever this file is updated with a change to maintainership. diff --git a/NOTICE b/NOTICE index 42b4e2c8..7501c75f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ FDC3 Java API - FINOS -Copyright 2023 - 2023 Wellington Management Company LLP open-source@wellington.com +Copyright 2023 - 2026 Wellington Management Company LLP open-source@wellington.com This product includes software developed at the Fintech Open Source Foundation (https://www.finos.org/). diff --git a/README.md b/README.md index 425e8694..3c799e75 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,189 @@ -![badge-labs](https://user-images.githubusercontent.com/327285/230928932-7c75f8ed-e57b-41db-9fb7-a292a13a1e58.svg) +[![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/lifecycle-stages/incubating) # FDC3 Java API -Standardized Java API to enable integration of FDC3 for Java Desktop Applications. +A Java implementation of the [FDC3 Standard](https://fdc3.finos.org/) enabling Java desktop applications to interoperate with other FDC3-enabled applications via the [Desktop Agent Communication Protocol (DACP)](https://fdc3.finos.org/docs/api/specs/desktopAgentCommunicationProtocol). -## Installation & Development Setup +```mermaid +sequenceDiagram + participant DA as Desktop Agent + participant App as Java App -Prerequisite: Java 11 + Note over DA: Advertise WebSocket URL and a pairing secret in the UI + DA-->>App: webSocketUrl + sharedSecret (copied by user, or passed as launch params) + Note over App: Build GetAgentParams -#### FDC3 Java API + App->>DA: WebSocket connect + DA->>App: Connection accepted + App->>DA: WSCPApplicationConnect (sharedSecret) -In a new terminal, navigate to the `fdc3api` directory + alt secret recognised + DA->>App: WSCPDesktopAgentConnect (appMetadata: appId, instanceId) + else secret invalid/unknown + DA->>App: WSCPConnectFailed + end -Build Project + loop DACP message exchange + App->>DA: broadcastRequest, addContextListenerRequest, etc. + DA->>App: broadcastEvent, intentEvent, heartbeatEvent, etc. + end -```sh -mvn clean compile + App->>DA: WSCPGoodbye ``` -#### FDC3 Container +**App identity flow:** this project implements the [WebSocket Connection Protocol (WSCP)](https://fdc3.finos.org/docs/api/specs/webSocketConnectionProtocol), which is how an application outside the browser connects to a Desktop Agent. It is a different protocol from the browser-resident Web Connection Protocol (WCP), and none of the WCP concepts — iframes, `identityUrl` origin matching, `instanceUuid` — apply here. -In a new terminal, navigate to the `fdc3container` directory +Identity rests on a **pairing secret**. The Desktop Agent generates a secret and makes it available to the user together with its WebSocket URL, typically by displaying both in its UI; how it does this is up to the agent. The application supplies the two values in `GetAgentParams` and sends the secret in `WSCPApplicationConnect`. The Desktop Agent checks the secret and replies with `WSCPDesktopAgentConnect` carrying the `appId` and `instanceId` it has assigned, or rejects the connection with `WSCPConnectFailed`. The assigned identity is then available through `getInfo()`. After the handshake, all FDC3 API calls travel as DACP messages over the same WebSocket. -Install Dependencies +## Overview -```sh -npm i -``` +This project provides: -Run Application +- **FDC3 Standard API interfaces** — Java equivalents of the FDC3 TypeScript API +- **Desktop Agent Proxy** — Client-side implementation that communicates with a Desktop Agent over WebSocket +- **GetAgent factory** — Simple entry point for connecting to a Desktop Agent +- **Cucumber testing framework** — Shared step definitions for conformance testing against the official FDC3 feature files -```sh -npm start -``` +## Modules + +| Module | Description | +| ------------------ | ------------------------------------------------------------------------------- | +| `fdc3-standard` | Core FDC3 API interfaces (`DesktopAgent`, `Channel`, `Context`, `Intent`, etc.) | +| `fdc3-schema` | Generated schema types and JSON conversion utilities | +| `fdc3-context` | Context type conversion utilities | +| `fdc3-agent-proxy` | `DesktopAgentProxy` implementation using DACP messaging | +| `fdc3-get-agent` | `GetAgent` factory for obtaining a `DesktopAgent` connection via WebSocket | -Runs on +## Requirements -#### Client +- Java 17 or later +- Maven 3.6+ +- A running FDC3 Desktop Agent that supports the [Desktop Agent Communication Protocol](https://fdc3.finos.org/docs/api/specs/desktopAgentCommunicationProtocol) (e.g., [FDC3 Sail](https://github.com/finos/FDC3-Sail)) -In a new terminal, navigate to the `client` directory +Building additionally requires **network access to the npm registry**, and no Node installation +of your own. See below. -Build Project: +## Installation + +### Building from Source ```sh -mvn clean compile package +mvn clean install ``` -Run the executable from Target directory +### Maven Dependency -```sh -java -jar \client\target\client-1.0.0-SNAPSHOT.jar - ``` +Once published, add to your `pom.xml`: -#### Stock Search React Receiver Application +```xml + + org.finos.fdc3 + fdc3-get-agent + 1.0.0-SNAPSHOT + +``` -In a new terminal, navigate to the `fdcreceiver-react-trade-app` directory +## Usage -Install Dependencies +### Connecting to a Desktop Agent -```sh -npm i -``` +```java +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.getagent.GetAgent; +import org.finos.fdc3.getagent.GetAgentParams; -Run Application +// Both values come from the Desktop Agent, which normally shows them in its UI. +GetAgentParams params = GetAgentParams.builder() + .webSocketUrl("wss://desktop-agent.example.com/fdc3/ws") // required + .sharedSecret(pairingSecret) // required + .channelSelector(myChannelSelector) // optional + .intentResolver(myIntentResolver) // optional + .build(); -```sh -npm start +DesktopAgent agent = GetAgent.getAgent(params).toCompletableFuture().get(); ``` -Runs on +The connection is a WebSocket, so `webSocketUrl` must use the `wss` scheme. Plain `ws` is +rejected unless the host is a loopback address, because the pairing secret and every +subsequent message would otherwise cross the network in the clear. To use `ws` against a +non-loopback host during development, opt in explicitly with +`.allowInsecureTransport(true)`. + +#### Handling the pairing secret + +The pairing secret is a bearer credential: anything holding it can connect to the Desktop +Agent as your application. Treat it accordingly. -## Usage with the Current State of this Repo +- Do not commit it, and do not write it to a log or an error message. This library redacts it + from its own logging, but it cannot redact what your application does with it. +- Prefer passing it through a launch parameter, a prompt, or a secret store over a command-line + argument, since arguments are visible to other processes on the machine. +- It is scoped to one app instance in one FDC3 session, so the same secret can be + reused to reconnect after an interruption. Persist it for the life of the instance; + this API cannot rotate it. -With the goal of our use case being to enable integration of FDC3 for Java Desktop Applications, we developed the Java API in addition to several simple applications that demonstrate its functionality and potential. The components we developed are as follows: +### Configuration via System Properties -* Java API - Our implementation of the Java API. Located in `fdc3api` -* Java Swing Sender - Client application to place orders. Located in `client` -* Adapter - the OpenFin Adapter. Located in `openfin-fdc3-adapter` -* Trade App - React based application enabled for receiving trade context from the sender. Located in `fdcreceiver-react-trade-app` -* FDC3 Container - OpenFin based container hosting the receiver environment. Located in `fdc3container` +These system properties supply defaults for `GetAgentParams`. Anything set on the builder wins. -As you interact with these applications, you will see our API in action. For example, say the user were to send the instruments from the Java Swing blotter, this action would then be reflected across the receiving web applications. In addition, we implemented a feature to allow the user to select what channel they are listening on to demonstrate the potential of our API. +| System Property | Description | +| ------------------------- | -------------------------------------------------- | +| `FDC3_WEBSOCKET_URL` | WebSocket endpoint of the Desktop Agent | +| `FDC3_CONNECTION_SECRET` | Pairing secret issued by the Desktop Agent | -![Demo Screenshot](readme-images/demo_screenshot.png) +With both set, only the optional overrides need to be given: -## Usage in a Business Environment +```java +GetAgentParams params = GetAgentParams.builder() + .channelSelector(myChannelSelector) + .build(); +``` -Some firms have existing Java desktop applications, and they want to use FDC3 to integrate with other apps that use JavaScript or other technologies. +### Broadcasting Context -For example, a buy-side trader using an internal Java order management system selects an order on their blotter and wants to view related analytics in an external JavaScript app provided by a broker. +```java +Context contact = new Context("fdc3.contact", "Jane Smith", + Map.of("email", "jane@example.com")); -This API will provide a standardized API for Java app developers to use, making it easier to switch the underlying technology that provides the FDC3 communication if required. By leveraging our FDC3 Java API in existing apps, developers will be able to create a user friendly workflow that favors shared context between applications as opposed to manual repetition by the user. +agent.broadcast(contact); +``` -## Roadmap +### Listening for Context -1. Robust testing -2. Acceptance as a FINOS standard -3. The FDC3 Java API is leveraged in a production environment -4. Review with OpenFin the FDC3 features not currently supported by their Java API. Discuss if they would be willing to implement this FDC3 Java API directly instead of using an adapter. -5. If possible, write a fully open-source implementation of the API without any dependency on a specific desktop agent vendor. This may be possible using websocket with the new desktop agent bridging spec. +```java +agent.addContextListener("fdc3.contact", (context, metadata) -> { + System.out.println("Received contact: " + context.get("name")); +}); +``` + +### Raising Intents + +```java +// A null target app lets the Desktop Agent's resolver choose. +IntentResolution resolution = + agent.raiseIntent("ViewChart", instrument, null).toCompletableFuture().get(); +``` ## Contributing -1. Fork it () +For any questions, bugs or feature requests please open an [issue](https://github.com/finos-labs/fdc3-java-api/issues). + +To submit a contribution: + +1. Fork the repository () 2. Create your feature branch (`git checkout -b feature/fooBar`) -3. Read our [contribution guidelines](.github/CONTRIBUTING.md) and [Community Code of Conduct](https://www.finos.org/code-of-conduct) +3. Read our [contribution guidelines](CONTRIBUTING.md) and [Community Code of Conduct](CODE_OF_CONDUCT.md) 4. Commit your changes (`git commit -am 'Add some fooBar'`) 5. Push to the branch (`git push origin feature/fooBar`) 6. Create a new Pull Request -_NOTE:_ Commits and pull requests to FINOS repositories will only be accepted from those contributors with an active, executed Individual Contributor License Agreement (ICLA) with FINOS OR who are covered under an existing and active Corporate Contribution License Agreement (CCLA) executed with FINOS. Commits from individuals not covered under an ICLA or CCLA will be flagged and blocked by the FINOS Clabot tool. Please note that some CCLAs require individuals/employees to be explicitly named on the CCLA. +_NOTE:_ Pull requests must follow this repository's contribution policy. FINOS projects use **CLA** via [EasyCLA](https://community.finos.org/docs/governance/Software-Projects/easycla). Read [FINOS Contribution Requirements](https://community.finos.org/docs/governance/Software-Projects/contribution-compliance-requirements) and [CONTRIBUTING.md](CONTRIBUTING.md) before contributing. -*Need an ICLA? Unsure if you are covered under an existing CCLA? Email [help@finos.org](mailto:help@finos.org)* +_Need an ICLA? Unsure if you are covered under an existing CCLA? Email [help@finos.org](mailto:help@finos.org)_ ## License -Copyright 2023 Wellington Management Company LLP +Copyright 2026 Fintech Open Source Foundation (FINOS) Distributed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..cb957fd2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +This project supports responsible disclosure of security vulnerabilities and adheres to the [FINOS Security Vulnerabilities Responsible Disclosure Policy](https://community.finos.org/docs/governance/software-projects/cve-responsible-disclosure). If you believe you have found a security vulnerability in this project, we encourage and appreciate your report. Please report it privately using one of the methods below — **do not** open a public GitHub Issue or otherwise disclose it publicly. + +## Reporting a Vulnerability + +- **GitHub private vulnerability reporting (preferred):** Use the ["Report a vulnerability"](../../security/advisories/new) button under this repository's **Security** tab. This opens a private advisory and communication channel with the maintainers. +- **Email:** If you're unable to use GitHub's private reporting, email [security@finos.org](mailto:security@finos.org) with a description of the issue. If maintainers are listed in [MAINTAINERS.md](MAINTAINERS.md), you may also email them and cc [security@finos.org](mailto:security@finos.org). + +## Vulnerability Process + +1. **Report the vulnerability privately** using one of the methods above. +2. The project team will acknowledge receipt, triage the report, and — if confirmed — work with you to investigate and develop a fix. +3. Once a fix is available, it will be released and the vulnerability will be publicly disclosed in accordance with the [FINOS Security Vulnerabilities Responsible Disclosure Policy](https://community.finos.org/docs/governance/software-projects/cve-responsible-disclosure). + +Thank you for helping keep FINOS projects and their users secure. diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..09e25c87 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +## TODO + +- Download Proxy feature files from npm (once they are published there) diff --git a/client/pom.xml b/client/pom.xml deleted file mode 100644 index 4bb2da63..00000000 --- a/client/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - 4.0.0 - - com.finos.fdc3.api - finos-bmo-hackathon - 1.0.0-SNAPSHOT - - - client - - - UTF-8 - 11 - 11 - 4.11 - 1.2.3 - 2.9.8 - 1.7.25 - 3.10.1 - ${basedir}/keystore.jks - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - ${jdk.source.version} - ${jdk.target.version} - - - - maven-assembly-plugin - - - prepare-package - - single - - - - - false - - jar-with-dependencies - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.8.1 - - - org.apache.maven.plugins - maven-shade-plugin - 3.4.1 - - - package - - shade - - - - - com.finos.fdc3.client.launcher.FDC3JavaAPIDemoApplication - - - - - - - - - - - junit - junit - ${junit.version} - test - - - org.apache.poi - poi - ${poi.version} - - - org.apache.poi - poi-ooxml - ${poi.version} - - - com.finos.fdc3.api - openfin-fdc3-adapter - ${project.version} - compile - - - diff --git a/client/src/main/java/com/finos/fdc3/client/AppUI.java b/client/src/main/java/com/finos/fdc3/client/AppUI.java deleted file mode 100644 index f0e3ee2b..00000000 --- a/client/src/main/java/com/finos/fdc3/client/AppUI.java +++ /dev/null @@ -1,308 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client; - -import com.finos.fdc3.client.handler.DataLoadHandler; -import com.finos.fdc3.client.handler.SystemChannelHandler; -import com.finos.fdc3.client.model.IncomingDataTableModel; -import com.finos.fdc3.client.model.SnPTableModel; -import com.finos.fdc3.client.publisher.OrderMessagePublisher; -import com.finos.fdc3.client.model.OrderTableModel; -import com.finos.fdc3.client.utils.SwingUtils; - -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.JTable; -import javax.swing.KeyStroke; -import javax.swing.ListSelectionModel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Event; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.Arrays; -import java.util.logging.Logger; - -public class AppUI -{ -static Logger logger = Logger.getLogger(AppUI.class.getName()); - -private JFrame frame = null; -private final Dimension PREFERRED_SIZE = new Dimension(500, 300); - -private JComboBox channelList = new JComboBox(Arrays.asList("","green","purple", "orange","red","pink","yellow").toArray()); - -private SystemChannelHandler systemChannelHandler = new SystemChannelHandler(channelList); - -//Order Data -private OrderTableModel orderTableModel = new OrderTableModel(); -private JTable orderTable = new JTable(orderTableModel); -private OrderMessagePublisher orderMessagePublisher; - -// -private IncomingDataTableModel incomingDataTableModel = new IncomingDataTableModel(); -private JTable incomingDataTable = new JTable(incomingDataTableModel); - -//SnP Data -private SnPTableModel snpTableModel = new SnPTableModel(); -private JTable snpTable = new JTable(snpTableModel); - -private JTabbedPane orderTabbedPane; -private DataLoadHandler dataLoadHandler = new DataLoadHandler(orderTableModel, snpTableModel); - -public void init() -{ - orderMessagePublisher = new OrderMessagePublisher(); - orderMessagePublisher.setAppUI(this); - orderTabbedPane = new JTabbedPane(); - orderTabbedPane.addTab( - "Blotter", - getOrCreateOrderComponent() - ); - orderTabbedPane.addTab( - "S&P500", - getOrCreateSnPComponent() - ); - orderTabbedPane.addTab( - "Incoming Data", - getOrIncomingDataComponent() - ); - orderTabbedPane.addChangeListener(new ChangeListener() - { - @Override - public void stateChanged(ChangeEvent e) - { - dataLoadHandler.setSelectedIndex(orderTabbedPane.getSelectedIndex()); - } - }); - // create frame - frame = new JFrame("FDC3-Java-API-Demo-App"); - frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - frame.addWindowListener(new WindowAdapter() - { - public void windowClosing(WindowEvent e) - { - exit(); - } - }); - frame.setJMenuBar(getOrCreateMenuComponent()); - frame.getContentPane().setLayout(new BorderLayout()); - - - JPanel tabbedPanel = new JPanel(); - tabbedPanel.setLayout(SwingUtils.createVBox(tabbedPanel)); - tabbedPanel.add(orderTabbedPane); - tabbedPanel.setPreferredSize(PREFERRED_SIZE); - frame.getContentPane().add(tabbedPanel, BorderLayout.CENTER); - - JPanel operationalPanel = new JPanel(); - JButton loadOrders = new JButton("load Sample data"); - loadOrders.addActionListener(dataLoadHandler); - operationalPanel.add(loadOrders); - - JButton button = new JButton("Send"); - button.addActionListener(orderMessagePublisher); - operationalPanel.add(button); - frame.getContentPane().add(operationalPanel, BorderLayout.SOUTH); - - frame.getContentPane().add(getSystemChannelPanel(), BorderLayout.NORTH); - - - frame.pack(); - frame.setVisible(true); - frame.toFront(); -} - - -private JPanel getSystemChannelPanel(){ - JPanel panel = new JPanel(); - panel.add(new JLabel("System Channels ")); - panel.add(channelList); - - JButton joinBtn = new JButton("Join"); - joinBtn.addActionListener(systemChannelHandler); - panel.add(joinBtn); - - return panel; -} - -public SystemChannelHandler getSystemChannelHandler() -{ - return systemChannelHandler; -} - -private OrderTableModel getOrderTableModel() -{ - return orderTableModel; -} - -public OrderMessagePublisher getOrderMessagePublisher() -{ - return orderMessagePublisher; -} - -private JScrollPane getOrCreateOrderComponent() -{ - getOrderMessagePublisher().setOrderTable(orderTable); - orderTable.setPreferredScrollableViewportSize(new Dimension(300,400)); - orderTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - JScrollPane orderScrollPane = new JScrollPane(orderTable); - orderScrollPane.getViewport().setBackground(Color.WHITE); - return orderScrollPane; -} -private JScrollPane getOrIncomingDataComponent() -{ - incomingDataTable.setPreferredScrollableViewportSize(new Dimension(300,400)); - incomingDataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - JScrollPane orderScrollPane = new JScrollPane(incomingDataTable); - orderScrollPane.getViewport().setBackground(Color.WHITE); - return orderScrollPane; -} - -private JScrollPane getOrCreateSnPComponent() -{ - snpTable.setPreferredScrollableViewportSize(new Dimension(300,400)); - snpTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - JScrollPane orderScrollPane = new JScrollPane(snpTable); - orderScrollPane.getViewport().setBackground(Color.WHITE); - return orderScrollPane; -} - -private JMenuBar getOrCreateMenuComponent() -{ - JMenuBar menuBar = new JMenuBar(); - JMenu fileMenu = new JMenu("File"); - fileMenu.setMnemonic(KeyEvent.VK_F); - JMenuItem fileRefreshAllMenuItem = new JMenuItem("Refresh All"); - fileRefreshAllMenuItem.setMnemonic(KeyEvent.VK_R); - fileRefreshAllMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, Event.CTRL_MASK)); - fileRefreshAllMenuItem.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - //TODO - } - }); - JMenuItem exitMenuItem = new JMenuItem("Exit"); - exitMenuItem.setMnemonic(KeyEvent.VK_X); - exitMenuItem.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - exit(); - } - }); - fileMenu.add(fileRefreshAllMenuItem); - fileMenu.addSeparator(); - fileMenu.add(exitMenuItem); - menuBar.add(fileMenu); - - JMenu actionsMenu = new JMenu("Actions"); - actionsMenu.setMnemonic(KeyEvent.VK_A); - JMenuItem actionsRefreshAllMenuItem = new JMenuItem("Refresh All"); - actionsRefreshAllMenuItem.setMnemonic(KeyEvent.VK_R); - actionsRefreshAllMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, Event.CTRL_MASK)); - actionsRefreshAllMenuItem.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - //TODO - } - }); - actionsMenu.add(actionsRefreshAllMenuItem); - menuBar.add(actionsMenu); - - JMenu helpMenu = new JMenu("Help"); - helpMenu.setMnemonic(KeyEvent.VK_H); - JMenuItem aboutMenu = new JMenuItem("About"); - aboutMenu.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - //TODO - } - }); - helpMenu.add(aboutMenu); - menuBar.add(SwingUtils.createHorizontalGlue()); - menuBar.add(helpMenu); - - return menuBar; -} - -public JFrame getFrame() -{ - return frame; -} - -private void exit() -{ - if (AppUI.this.showConfirmWarningDialog( - "Are you sure you want to exit the applicaton ?") == JOptionPane.YES_OPTION) { - if (frame != null) { - frame.dispose(); - frame = null; - } - System.exit(0); - } -} - -public int showConfirmWarningDialog(String message) -{ - return JOptionPane.showConfirmDialog( - getFrame(), - message, - "Confirm", - JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE - ); -} - -public IncomingDataTableModel getIncomingDataTableModel() -{ - return incomingDataTableModel; -} - -public JTabbedPane getOrderTabbedPane() -{ - return orderTabbedPane; -} - -public SnPTableModel getSnpTableModel() -{ - return snpTableModel; -} - -public JTable getSnpTable() -{ - return snpTable; -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/data/IncomingData.java b/client/src/main/java/com/finos/fdc3/client/data/IncomingData.java deleted file mode 100644 index 162021d8..00000000 --- a/client/src/main/java/com/finos/fdc3/client/data/IncomingData.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.data; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.math.BigDecimal; - -@JsonInclude(JsonInclude.Include.NON_DEFAULT) -@JsonPropertyOrder({ - "name", - "ticker", - "ric", - "isin" -}) -@JsonIgnoreProperties(ignoreUnknown = true) -public class IncomingData { - private String name; - private String ticker; - private String ric; - private String isin; - private BigDecimal holding; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getTicker() { - return ticker; - } - - public void setTicker(String ticker) { - this.ticker = ticker; - } - - public String getRic() { - return ric; - } - - public void setRic(String ric) { - this.ric = ric; - } - - public String getIsin() { - return isin; - } - - public void setIsin(String isin) { - this.isin = isin; - } - - public BigDecimal getHolding() { - return holding; - } - - public void setHolding(BigDecimal holding) { - this.holding = holding; - } -} - diff --git a/client/src/main/java/com/finos/fdc3/client/data/OrderData.java b/client/src/main/java/com/finos/fdc3/client/data/OrderData.java deleted file mode 100644 index d9fcdd60..00000000 --- a/client/src/main/java/com/finos/fdc3/client/data/OrderData.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.data; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.math.BigDecimal; -import java.util.Objects; - -@JsonInclude(JsonInclude.Include.NON_DEFAULT) -@JsonPropertyOrder({ - "orderId", - "symbol", - "side", - "orderQty", - "side", - "trader" -}) -@JsonIgnoreProperties(ignoreUnknown=true) -public class OrderData -{ -private long orderId; -private String symbol; -private BigDecimal orderQty; -private String side; -private String trader; - -public long getOrderId() -{ - return orderId; -} - -public void setOrderId(long orderId) -{ - this.orderId = orderId; -} - -public String getSymbol() -{ - return symbol; -} - -public void setSymbol(String symbol) -{ - this.symbol = symbol; -} - -public BigDecimal getOrderQty() -{ - return orderQty; -} - -public void setOrderQty(BigDecimal orderQty) -{ - this.orderQty = orderQty; -} - -public String getSide() -{ - return side; -} - -public void setSide(String side) -{ - this.side = side; -} - -public String getTrader() -{ - return trader; -} - -public void setTrader(String trader) -{ - this.trader = trader; -} - -@Override -public boolean equals(Object o) -{ - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OrderData orderData = (OrderData) o; - return orderId == orderData.orderId; -} - -@Override -public int hashCode() -{ - return Objects.hash(orderId); -} - -} diff --git a/client/src/main/java/com/finos/fdc3/client/data/SnPData.java b/client/src/main/java/com/finos/fdc3/client/data/SnPData.java deleted file mode 100644 index c780d425..00000000 --- a/client/src/main/java/com/finos/fdc3/client/data/SnPData.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.data; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.Objects; - -@JsonInclude(JsonInclude.Include.NON_DEFAULT) -@JsonPropertyOrder({ - "Symbol", - "Name", - "Sector" -}) -@JsonIgnoreProperties(ignoreUnknown=true) -public class SnPData -{ -private String sector; -private String name; -private String symbol; - -@JsonProperty("Sector") -public String getSector() -{ - return sector; -} - -public void setSector(String sector) -{ - this.sector = sector; -} - -@JsonProperty("Name") -public String getName() -{ - return name; -} - -public void setName(String name) -{ - this.name = name; -} - -@JsonProperty("Symbol") -public String getSymbol() -{ - return symbol; -} - -public void setSymbol(String symbol) -{ - this.symbol = symbol; -} - -@Override -public boolean equals(Object o) -{ - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - SnPData snPData = (SnPData) o; - return sector.equals(snPData.sector) && name.equals(snPData.name) && symbol.equals(snPData.symbol); -} - -@Override -public int hashCode() -{ - return Objects.hash(sector, name, symbol); -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/handler/DataLoadHandler.java b/client/src/main/java/com/finos/fdc3/client/handler/DataLoadHandler.java deleted file mode 100644 index 6f1a7f0f..00000000 --- a/client/src/main/java/com/finos/fdc3/client/handler/DataLoadHandler.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.handler; - -import com.finos.fdc3.client.data.OrderData; -import com.finos.fdc3.client.data.SnPData; -import com.finos.fdc3.client.model.OrderTableModel; -import com.finos.fdc3.client.model.SnPTableModel; -import com.finos.fdc3.client.utils.SampleDataLoaderUtil; -import com.finos.fdc3.client.utils.SwingUtils; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Collection; - -public class DataLoadHandler implements ActionListener -{ - -private final OrderTableModel orderTableModel; -private final SnPTableModel snPTableModel; - -private int selectedIndex; - -public DataLoadHandler(OrderTableModel orderTableModel, SnPTableModel snPTableModel) { - this.orderTableModel = orderTableModel; - this.snPTableModel = snPTableModel; -} - -public OrderTableModel getOrderTableModel() -{ - return orderTableModel; -} - -public SnPTableModel getSnPTableModel() -{ - return snPTableModel; -} - -public int getSelectedIndex() -{ - return selectedIndex; -} - -public void setSelectedIndex(int selectedIndex) -{ - this.selectedIndex = selectedIndex; -} - -@Override -public void actionPerformed(ActionEvent e) -{ - SwingUtils.invokeLater(new Runnable() - { - @Override - public void run() - { - switch (getSelectedIndex()){ - case 0: loadOrderData();break; - case 1: loadSnPData();break; - default: - } - } - }); -} - - - -private void loadSnPData() -{ - if(getSnPTableModel().getRowCount() == 0) { - Collection dataList = SampleDataLoaderUtil.readSPData(); - if (dataList != null && dataList.size() > 0) { - dataList.forEach(o -> { - getSnPTableModel().addData(o); - }); - } - } -} -private void loadOrderData() -{ - Collection orders = SampleDataLoaderUtil.loadSampleData(); - if(orders!=null && orders.size() > 0) { - orders.forEach(o->{ - getOrderTableModel().addData(o); - }); - } -} - -} diff --git a/client/src/main/java/com/finos/fdc3/client/handler/SystemChannelHandler.java b/client/src/main/java/com/finos/fdc3/client/handler/SystemChannelHandler.java deleted file mode 100644 index 7c59e9a4..00000000 --- a/client/src/main/java/com/finos/fdc3/client/handler/SystemChannelHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.handler; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.List; -import java.util.stream.Collectors; - -import javax.swing.DefaultComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.SwingUtilities; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.api.DesktopAgent; -import com.finos.fdc3.api.channel.Channel; - -public class SystemChannelHandler implements ActionListener -{ -private static final Logger LOGGER = LoggerFactory.getLogger(SystemChannelHandler.class); -private final JComboBox connectionsList; -private DesktopAgent desktopAgent; - -public SystemChannelHandler(JComboBox connectionsList){ - this.connectionsList = connectionsList; -} - -public DesktopAgent getDesktopAgent() { - - return desktopAgent; -} - -public void setDesktopAgent(DesktopAgent desktopAgent) { - - this.desktopAgent = desktopAgent; - loadChannels(); -} - -public JComboBox getConnectionsList() -{ - return connectionsList; -} - -public void actionPerformed(ActionEvent e) -{ - if(getDesktopAgent()==null) { - LOGGER.error("Error Desktop agent is null"); - return; - } - joinChannel((String)getConnectionsList().getSelectedItem()); -} - -private void joinChannel(String channel) -{ - desktopAgent.joinUserChannel(channel).thenRun(() -> LOGGER.info("Joined {} channel", channel)) - .exceptionally(ex -> { - LOGGER.error("Error joining FDC3 channel", ex); - return null; - }); -} - -private void loadChannels() { - - desktopAgent.getUserChannels().thenAccept(channelList -> { - List channelIds = channelList.stream().map(Channel::getId).collect(Collectors.toList()); - LOGGER.info("Loaded channels: {}", channelIds); - SwingUtilities.invokeLater(() -> { - DefaultComboBoxModel model = new DefaultComboBoxModel<>(); - model.addAll(channelIds); - model.setSelectedItem(null); - getConnectionsList().setModel(model); - }); - }).exceptionally(ex -> { - LOGGER.error("Error loading channels", ex); - return null; - }); -} - -} diff --git a/client/src/main/java/com/finos/fdc3/client/launcher/FDC3JavaAPIDemoApplication.java b/client/src/main/java/com/finos/fdc3/client/launcher/FDC3JavaAPIDemoApplication.java deleted file mode 100644 index 8d87c59a..00000000 --- a/client/src/main/java/com/finos/fdc3/client/launcher/FDC3JavaAPIDemoApplication.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.launcher; - -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.context.Instrument; -import com.finos.fdc3.api.metadata.ContextMetadata; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.client.data.IncomingData; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.adapter.openfin.OpenFinDesktopAgent; -import com.finos.fdc3.adapter.openfin.OpenFinFDC3Config; -import com.finos.fdc3.api.DesktopAgent; -import com.finos.fdc3.client.AppUI; -import com.openfin.desktop.RuntimeConfiguration; -import com.finos.fdc3.api.context.Position; - -import java.math.BigDecimal; - -public class FDC3JavaAPIDemoApplication -{ - -private static final Logger LOGGER = LoggerFactory.getLogger(FDC3JavaAPIDemoApplication.class); - -private static DesktopAgent desktopAgent; - -public static void main(String[] arg) -{ - try { - //1. Build UI - AppUI ui = new AppUI(); - ui.init(); - - // 2. FDC3 Desktop Agent - DesktopAgent desktopAgent = createDesktopAgent(); - ui.getOrderMessagePublisher().setDesktopAgent(desktopAgent); - ui.getSystemChannelHandler().setDesktopAgent(desktopAgent); - desktopAgent.addContextListener(Instrument.TYPE, new ContextHandler() - { - @Override - public void handleContext(Context context, ContextMetadata metadata) - { - LOGGER.info(String.format("Received the context :%s", context)); - try { - IncomingData data = new IncomingData(); - data.setName(context.getName()); - data.setIsin((String) context.getId().getOrDefault("ISIN", null)); - data.setRic((String)context.getId().getOrDefault("RIC", null)); - data.setTicker((String)context.getId().getOrDefault("ticker", null)); - ui.getIncomingDataTableModel().addData(data); - }catch (Throwable t) { - LOGGER.error(String.format("Unable to handle the request :%s ", context)); - } - } - }); - - desktopAgent.addContextListener("fdc3.position", new ContextHandler() - { - @Override - public void handleContext(Context context, ContextMetadata metadata) - { - LOGGER.info(String.format("Received the context :%s", context)); - try { - IncomingData data = new IncomingData(); - Position position = (Position)context; - data.setName(position.getName()); - Instrument instrument = position.getInstrument(); - if(instrument!=null && instrument.getId()!=null) { - - data.setIsin((String)context.getId().getOrDefault("ISIN", null)); - data.setRic((String)context.getId().getOrDefault("RIC", null)); - data.setTicker((String)context.getId().getOrDefault("ticker", null)); - } - data.setHolding(position.getHolding()); - ui.getIncomingDataTableModel().addData(data); - }catch (Throwable t) { - LOGGER.error("Unable to handle the request : {}", context, t); - } - } - }); - - } catch (Exception t) { - LOGGER.error("Unable to launch application", t); - } -} - -private static DesktopAgent createDesktopAgent() { - - OpenFinFDC3Config fdc3Config = new OpenFinFDC3Config(); - fdc3Config.setUuid("fdc3-java-demo"); - fdc3Config.setBrokerName("fdc3-platform"); - RuntimeConfiguration runtimeConfig = new RuntimeConfiguration(); - runtimeConfig.setRuntimeVersion("22.94.66.4"); - fdc3Config.setRuntimeConfiguration(runtimeConfig); - desktopAgent = new OpenFinDesktopAgent(fdc3Config); - return desktopAgent; -} - -} \ No newline at end of file diff --git a/client/src/main/java/com/finos/fdc3/client/model/IncomingDataTableModel.java b/client/src/main/java/com/finos/fdc3/client/model/IncomingDataTableModel.java deleted file mode 100644 index 1187cbe0..00000000 --- a/client/src/main/java/com/finos/fdc3/client/model/IncomingDataTableModel.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.model; - -import com.finos.fdc3.client.data.IncomingData; -import com.finos.fdc3.client.data.OrderData; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.List; - -public class IncomingDataTableModel extends AbstractTableModel -{ - -private List dataList = new ArrayList(); -private String[] columnNames = { "Name", "Ticker", "RIC", "ISIN" , "Stock Units (Held)"}; -public IncomingDataTableModel() {} - -public IncomingDataTableModel(List orderDataList) { - this.dataList = orderDataList; -} - -@Override -public String getColumnName(int column) { - return columnNames[column]; -} - -@Override -public int getColumnCount() { - return columnNames.length; -} - -@Override -public int getRowCount() { - return dataList.size(); -} - -@Override -public Object getValueAt(int row, int column) { - Object OrderDataAttribute = null; - IncomingData data = dataList.get(row); - switch(column) { - case 0: OrderDataAttribute = data.getName(); break; - case 1: OrderDataAttribute = data.getTicker(); break; - case 2: OrderDataAttribute = data.getRic(); break; - case 3: OrderDataAttribute = data.getIsin(); break; - case 4: OrderDataAttribute = data.getHolding(); break; - default: break; - } - return OrderDataAttribute; -} - -public void addData(IncomingData data) { - dataList.add(data); - fireTableDataChanged(); -} -public IncomingData getData(int row) { - return dataList.get(row); -} -} \ No newline at end of file diff --git a/client/src/main/java/com/finos/fdc3/client/model/OrderTableModel.java b/client/src/main/java/com/finos/fdc3/client/model/OrderTableModel.java deleted file mode 100644 index 9a67e9a9..00000000 --- a/client/src/main/java/com/finos/fdc3/client/model/OrderTableModel.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.model; - -import com.finos.fdc3.client.data.OrderData; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.List; - -public class OrderTableModel extends AbstractTableModel -{ - -private List orderDataList = new ArrayList(); -private String[] columnNames = { "Order ID", "Trader", "Side", "Symbol", "Quantity"}; - -public OrderTableModel() {} - -public OrderTableModel(List orderDataList) { - this.orderDataList = orderDataList; -} - -@Override -public String getColumnName(int column) { - return columnNames[column]; -} - -@Override -public int getColumnCount() { - return columnNames.length; -} - -@Override -public int getRowCount() { - return orderDataList.size(); -} - -@Override -public Object getValueAt(int row, int column) { - Object OrderDataAttribute = null; - OrderData OrderDataObject = orderDataList.get(row); - switch(column) { - case 0: OrderDataAttribute = OrderDataObject.getOrderId(); break; - case 1: OrderDataAttribute = OrderDataObject.getTrader(); break; - case 2: OrderDataAttribute = OrderDataObject.getSide(); break; - case 3: OrderDataAttribute = OrderDataObject.getSymbol(); break; - case 4: OrderDataAttribute = OrderDataObject.getOrderQty(); break; - default: break; - } - return OrderDataAttribute; -} - -public void addData(OrderData OrderData) { - orderDataList.add(OrderData); - fireTableDataChanged(); -} -public OrderData getData(int row) { - return orderDataList.get(row); -} -} \ No newline at end of file diff --git a/client/src/main/java/com/finos/fdc3/client/model/SnPTableModel.java b/client/src/main/java/com/finos/fdc3/client/model/SnPTableModel.java deleted file mode 100644 index 36c1f7e4..00000000 --- a/client/src/main/java/com/finos/fdc3/client/model/SnPTableModel.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.finos.fdc3.client.model; - -import com.finos.fdc3.client.data.SnPData; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.List; - -public class SnPTableModel extends AbstractTableModel -{ - -private List dataList = new ArrayList(); -private String[] columnNames = { "Name", "Sector", "Symbol"}; - -public SnPTableModel() {} - -public SnPTableModel(List SnPDataList) { - this.dataList = SnPDataList; -} - -@Override -public String getColumnName(int column) { - return columnNames[column]; -} - -@Override -public int getColumnCount() { - return columnNames.length; -} - -@Override -public int getRowCount() { - return dataList.size(); -} - -@Override -public Object getValueAt(int row, int column) { - Object SnPDataAttribute = null; - SnPData SnPDataObject = dataList.get(row); - switch(column) { - case 0: SnPDataAttribute = SnPDataObject.getName(); break; - case 1: SnPDataAttribute = SnPDataObject.getSector(); break; - case 2: SnPDataAttribute = SnPDataObject.getSymbol(); break; - default: break; - } - return SnPDataAttribute; -} - -public void addData(SnPData SnPData) { - dataList.add(SnPData); - fireTableDataChanged(); -} -public SnPData getData(int row) { - return dataList.get(row); -} - -} \ No newline at end of file diff --git a/client/src/main/java/com/finos/fdc3/client/publisher/OrderMessagePublisher.java b/client/src/main/java/com/finos/fdc3/client/publisher/OrderMessagePublisher.java deleted file mode 100644 index 9fd9c558..00000000 --- a/client/src/main/java/com/finos/fdc3/client/publisher/OrderMessagePublisher.java +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.publisher; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.JTable; - -import com.finos.fdc3.client.AppUI; -import com.finos.fdc3.client.data.SnPData; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.api.DesktopAgent; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.context.Instrument; -import com.finos.fdc3.api.utils.JacksonUtilities; -import com.finos.fdc3.client.data.OrderData; -import com.finos.fdc3.client.model.OrderTableModel; - -public class OrderMessagePublisher implements ActionListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(OrderMessagePublisher.class); - - private AppUI appUI; - - private DesktopAgent desktopAgent; - - private JTable orderTable; - - public JTable getOrderTable() { - - return orderTable; - } - - public void setOrderTable(JTable orderTable) { - - this.orderTable = orderTable; - } - - public AppUI getAppUI() - { - return appUI; - } - - public void setAppUI(AppUI appUI) - { - this.appUI = appUI; - } - - public OrderData getSelectedRowData() { - - int row = getOrderTable().getSelectedRow(); - if (row >= 0) { - return ((OrderTableModel) getOrderTable().getModel()).getData(row); - } - return null; - } - - public DesktopAgent getDesktopAgent() { - - return desktopAgent; - } - - public void setDesktopAgent(DesktopAgent desktopAgent) { - - this.desktopAgent = desktopAgent; - } - - @Override - public void actionPerformed(ActionEvent e) { - - int selectedTab = getAppUI().getOrderTabbedPane().getSelectedIndex(); - switch(selectedTab) { - case 0: sendOrderData(); break; - case 1: sendSnpData(); break; - default: - } - } - -private void sendSnpData() -{ - try { - int row = getAppUI().getSnpTable().getSelectedRow(); - if (row < 0) { - return; - } - SnPData snPData = getAppUI().getSnpTableModel().getData(row); - if (snPData == null) { - LOGGER.warn("snPData has not selected yet"); - return; - } - LOGGER.info("Selected snPData: {}", JacksonUtilities.serializeToString(snPData)); - if (getDesktopAgent() == null) { - LOGGER.warn("FDC3 Desktop Agent is not yet initialized"); - } else { - Context context = getApiContext(snPData); - LOGGER.info("Broadcasting to FDC3: {}", context); - getDesktopAgent().broadcast(context).thenRun(() -> LOGGER.debug("FDC3 broadcast complete")) - .exceptionally(ex -> { - LOGGER.error("Error broadcasting to FDC3", ex); - return null; - }); - //TODO raising an intent getDesktopAgent().raiseIntent("ViewQuote", context); - } - - } catch (Exception ex) { - LOGGER.error("Error broadcasting to FDC3", ex); - } -} - - -private void sendOrderData() - { - try { - OrderData selectedOrder = getSelectedRowData(); - if (selectedOrder == null) { - LOGGER.warn("Order has not selected yet"); - return; - } - LOGGER.info("Selected order: {}", JacksonUtilities.serializeToString(selectedOrder)); - if (getDesktopAgent() == null) { - LOGGER.warn("FDC3 Desktop Agent is not yet initialized"); - } else { - Context context = getApiContext(selectedOrder); - LOGGER.info("Broadcasting to FDC3: {}", context); - getDesktopAgent().broadcast(context).thenRun(() -> LOGGER.debug("FDC3 broadcast complete")) - .exceptionally(ex -> { - LOGGER.error("Error broadcasting to FDC3", ex); - return null; - }); - //TODO raising an intent getDesktopAgent().raiseIntent("ViewQuote", context); - } - - } catch (Exception ex) { - LOGGER.error("Error broadcasting to FDC3", ex); - } - } - - - public Context getApiContext(OrderData orderData) { - Context context = new Instrument(); - context.setName(orderData.getSymbol()); - Map id = new HashMap<>(); - id.put("ticker", orderData.getSymbol()); - context.setId(id); - return context; - } - -public Context getApiContext(SnPData orderData) { - Context context = new Instrument(); - context.setName(orderData.getName()); - Map id = new HashMap<>(); - id.put("ticker", orderData.getSymbol()); - context.setId(id); - return context; -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/utils/JSONAdapterUtil.java b/client/src/main/java/com/finos/fdc3/client/utils/JSONAdapterUtil.java deleted file mode 100644 index ed266f3e..00000000 --- a/client/src/main/java/com/finos/fdc3/client/utils/JSONAdapterUtil.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.utils; - -import com.sun.codemodel.JCodeModel; -import org.jsonschema2pojo.*; -import org.jsonschema2pojo.rules.RuleFactory; - -import java.io.File; -import java.io.IOException; -import java.net.URL; - -public class JSONAdapterUtil -{ - -public static void main(String[] arg) { - try { - convertJsonToJavaClass(new File("C:\\finos\\json-schema\\Sample-Json.json").toURI().toURL(), - new File("C:\\finos\\json-schema"), "com.finos.fdc3.java.api", - "Sample"); - }catch(Throwable t) { - t.printStackTrace(); - } -} - -public static void convertJsonToJavaClass(URL inputJsonUrl, File outputJavaClassDirectory, String packageName, String javaClassName) - throws IOException -{ - JCodeModel jcodeModel = new JCodeModel(); - - GenerationConfig config = new DefaultGenerationConfig() { - @Override - public boolean isGenerateBuilders() { - return true; - } - - @Override - public SourceType getSourceType() { - return SourceType.JSON; - } - }; - - SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(config), new SchemaStore()), new SchemaGenerator()); - mapper.generate(jcodeModel, javaClassName, packageName, inputJsonUrl); - - jcodeModel.build(outputJavaClassDirectory); -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/utils/SampleDataLoaderUtil.java b/client/src/main/java/com/finos/fdc3/client/utils/SampleDataLoaderUtil.java deleted file mode 100644 index 95df7503..00000000 --- a/client/src/main/java/com/finos/fdc3/client/utils/SampleDataLoaderUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.utils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.math.BigDecimal; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import com.finos.fdc3.api.utils.JacksonUtilities; -import com.finos.fdc3.client.data.OrderData; -import com.finos.fdc3.client.data.SnPData; - -public class SampleDataLoaderUtil -{ -private static int orderCounter = 101; -public static Collection loadSampleData() -{ - List orderDataList = new ArrayList<>(); - - OrderData data1 = new OrderData(); - data1.setOrderId(orderCounter++); - data1.setTrader("Demo User"); - data1.setSide("BUY"); - data1.setSymbol("IBM"); - data1.setOrderQty(new BigDecimal(10000)); - orderDataList.add(data1); - - OrderData data2 = new OrderData(); - data2.setOrderId(orderCounter++); - data2.setTrader("Demo User"); - data2.setSide("BUY"); - data2.setSymbol("YAHOO"); - data2.setOrderQty(new BigDecimal(10000)); - orderDataList.add(data2); - - OrderData data3 = new OrderData(); - data3.setOrderId(orderCounter++); - data3.setTrader("Demo User"); - data3.setSide("SELL"); - data3.setSymbol("IBM"); - data3.setOrderQty(new BigDecimal(10000)); - orderDataList.add(data3); - - OrderData data4 = new OrderData(); - data4.setOrderId(orderCounter++); - data4.setTrader("Demo User"); - data4.setSide("SELL"); - data4.setSymbol("YAHOO"); - data4.setOrderQty(new BigDecimal(10000)); - orderDataList.add(data4); - - return orderDataList; - -} - -public static List readSPData() -{ - try { - return JacksonUtilities.deserializeListFromString( - readData(new URL("https://pkgstore.datahub.io/core/s-and-p-500-companies/constituents_json/data/297344d8dc0a9d86b8d107449c851cc8/constituents_json.json")) - , SnPData.class); - }catch(Throwable t) { - - } - return Collections.emptyList(); -} - -private static String readData(URL url) throws IOException -{ - - try (InputStream input = url.openStream()) { - InputStreamReader isr = new InputStreamReader(input); - BufferedReader reader = new BufferedReader(isr); - StringBuilder json = new StringBuilder(); - int c; - while ((c = reader.read()) != -1) { - json.append((char) c); - } - return json.toString(); - } -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/utils/StringUtilities.java b/client/src/main/java/com/finos/fdc3/client/utils/StringUtilities.java deleted file mode 100644 index 122c4d91..00000000 --- a/client/src/main/java/com/finos/fdc3/client/utils/StringUtilities.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.utils; - -import com.finos.fdc3.api.utils.JacksonUtilities; - -public class StringUtilities -{ -public static String valueAsString(Object object) { - if (object == null) { - return null; - } else { - try { - return JacksonUtilities.getObjectMapper().writeValueAsString(object); - } catch (Throwable t) { - return "N/A"; - } - } -} -} diff --git a/client/src/main/java/com/finos/fdc3/client/utils/SwingUtils.java b/client/src/main/java/com/finos/fdc3/client/utils/SwingUtils.java deleted file mode 100644 index 44b3a276..00000000 --- a/client/src/main/java/com/finos/fdc3/client/utils/SwingUtils.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.client.utils; - -import com.finos.fdc3.client.AppGUIException; - -import javax.swing.*; -import java.awt.*; - -public final class SwingUtils -{ - -public static Component createHorizontalGlue() -{ - return Box.createHorizontalGlue(); -} - -public static final BoxLayout createVBox(Container container) -{ - return new BoxLayout(container, BoxLayout.Y_AXIS); -} - -public static final void invokeLater(Runnable r) -{ - SwingUtilities.invokeLater(r); -} - -public static final void invokeAndWait(Runnable r) - throws AppGUIException -{ - try { - SwingUtilities.invokeAndWait(r); - } - catch (Throwable t) { - throw new AppGUIException( - String.format( - "error executing invokeAndWait, details: %s - %s", - t.getMessage(), - t.getCause() - ) - ); - } -} - - -} \ No newline at end of file diff --git a/fdc3-agent-proxy/pom.xml b/fdc3-agent-proxy/pom.xml new file mode 100644 index 00000000..461f8859 --- /dev/null +++ b/fdc3-agent-proxy/pom.xml @@ -0,0 +1,192 @@ + + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-agent-proxy + FDC3 Desktop Agent Proxy + Desktop Agent Proxy implementation for FDC3 + + + ${project.build.directory}/npm-work/node_modules/@finos/fdc3-agent-proxy/test/features + + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + + + org.finos.fdc3 + fdc3-schema + ${project.version} + + + + org.finos + cucumber-testing-steps + test + + + + + io.cucumber + cucumber-spring + test + + + org.springframework + spring-context + test + + + org.springframework + spring-test + test + + + io.cucumber + cucumber-junit-platform-engine + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-suite + test + + + org.slf4j + slf4j-simple + test + + + + + org.slf4j + slf4j-api + + + + com.networknt + json-schema-validator + test + + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + copy-npm-manifest + generate-test-resources + + run + + + + + + + + + + + + + + + + + com.github.eirslett + frontend-maven-plugin + 1.15.0 + + ${node.version} + ${npm.version} + ${project.build.directory}/npm-work + ${project.build.directory}/node-installation + + + + install-node-and-npm + generate-test-resources + + install-node-and-npm + + + + npm-ci + generate-test-resources + + npm + + + ci --no-audit --no-fund + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + copy-published-features + generate-test-resources + + copy-resources + + + ${project.build.testOutputDirectory}/features + true + + + ${fdc3.features.npm.dir} + + *.feature + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + cucumber.junit-platform.naming-strategy=long + cucumber.junit-platform.discovery.as-root-engine=false + + + + + + + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/DesktopAgentProxy.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/DesktopAgentProxy.java new file mode 100644 index 00000000..4246a7f0 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/DesktopAgentProxy.java @@ -0,0 +1,253 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.api.ui.Connectable; +import org.finos.fdc3.proxy.apps.AppSupport; +import org.finos.fdc3.proxy.channels.ChannelSupport; +import org.finos.fdc3.proxy.heartbeat.HeartbeatSupport; +import org.finos.fdc3.proxy.intents.IntentSupport; + +/** + * Desktop Agent Proxy implementation. + *

+ * This splits out the functionality of the desktop agent into + * app, channels and intents concerns. + */ +public class DesktopAgentProxy implements DesktopAgent, Connectable { + + private final HeartbeatSupport heartbeat; + private final ChannelSupport channels; + private final IntentSupport intents; + private final AppSupport apps; + private final List connectables; + + public DesktopAgentProxy( + HeartbeatSupport heartbeat, + ChannelSupport channels, + IntentSupport intents, + AppSupport apps, + List connectables) { + this.heartbeat = heartbeat; + this.intents = intents; + this.channels = channels; + this.apps = apps; + this.connectables = connectables; + } + + @Override + public CompletionStage addEventListener(String type, EventHandler handler) { + return channels.addEventListener(handler, type); + } + + @Override + public CompletionStage getInfo() { + return apps.getImplementationMetadata(); + } + + @Override + public CompletionStage broadcast(Context context) { + return broadcast(context, null); + } + + @Override + public CompletionStage broadcast(Context context, AppProvidableContextMetadata metadata) { + return channels.getUserChannel() + .thenCompose(channel -> { + if (channel != null) { + return channel.broadcast(context, metadata); + } else { + return CompletableFuture.completedFuture(null); + } + }); + } + + @Override + public CompletionStage addContextListener(String contextType, ContextHandler handler) { + List types = contextType == null ? null : List.of(contextType); + return channels.addContextListener(handler, types); + } + + @Override + public CompletionStage addContextListener(List contextTypes, ContextHandler handler) { + // null is the String-overload "all types" signal. Reflective callers (and Java + // invoke with a null literal) cannot distinguish the overloads, so treat null + // here the same way rather than as an empty list. + if (contextTypes == null) { + return channels.addContextListener(handler, null); + } + return channels.addContextListener(handler, contextTypes); + } + + @Override + public CompletionStage> getUserChannels() { + return channels.getUserChannels(); + } + + @Override + public CompletionStage getOrCreateChannel(String channelId) { + return channels.getOrCreate(channelId); + } + + @Override + public CompletionStage createPrivateChannel() { + return channels.createPrivateChannel(); + } + + @Override + public CompletionStage leaveCurrentChannel() { + return channels.leaveUserChannel(); + } + + @Override + public CompletionStage joinUserChannel(String channelId) { + return channels.joinUserChannel(channelId); + } + + @Override + public CompletionStage> getCurrentChannel() { + return channels.getUserChannel() + .thenApply(Optional::ofNullable); + } + + @Override + public CompletionStage findIntent(String intent, Context context, String resultType) { + return intents.findIntent(intent, context, resultType); + } + + @Override + public CompletionStage> findIntentsByContext(Context context, String resultType) { + return intents.findIntentsByContext(context, resultType); + } + + @Override + public CompletionStage raiseIntent( + String intent, + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + return intents.raiseIntent(intent, context, app, newInstance, metadata); + } + + @Override + public CompletionStage addIntentListener(String intent, IntentHandler handler) { + return intents.addIntentListener(intent, handler); + } + + @Override + public CompletionStage addIntentListenerWithContext( + String intent, String contextType, IntentHandler handler) { + return intents.addIntentListenerWithContext(intent, List.of(contextType), handler); + } + + @Override + public CompletionStage addIntentListenerWithContext( + String intent, List contextTypes, IntentHandler handler) { + return intents.addIntentListenerWithContext(intent, contextTypes, handler); + } + + @Override + public CompletionStage raiseIntentForContext( + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + return intents.raiseIntentForContext(context, app, newInstance, metadata); + } + + @Override + public CompletionStage open(AppIdentifier app, Context context) { + return apps.open(app, context, null); + } + + @Override + public CompletionStage open(AppIdentifier app, Context context, AppProvidableContextMetadata metadata) { + return apps.open(app, context, metadata); + } + + @Override + public CompletionStage close() { + return apps.close(); + } + + @Override + public CompletionStage> findInstances(AppIdentifier app) { + return apps.findInstances(app); + } + + @Override + public CompletionStage getAppMetadata(AppIdentifier app) { + return apps.getAppMetadata(app); + } + + @Override + public CompletionStage disconnect() { + List> futures = connectables.stream() + .map(c -> c.disconnect().toCompletableFuture()) + .collect(Collectors.toList()); + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } + + @Override + public CompletionStage connect() { + List> futures = connectables.stream() + .map(c -> c.connect().toCompletableFuture()) + .collect(Collectors.toList()); + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } + + // Getters for internal components (useful for testing) + + public HeartbeatSupport getHeartbeat() { + return heartbeat; + } + + public ChannelSupport getChannels() { + return channels; + } + + public IntentSupport getIntents() { + return intents; + } + + public AppSupport getApps() { + return apps; + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/Messaging.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/Messaging.java new file mode 100644 index 00000000..774e2d65 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/Messaging.java @@ -0,0 +1,114 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy; + +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.function.Predicate; + +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.listeners.RegisterableListener; +import org.finos.fdc3.schema.AddContextListenerRequestMeta; +import org.finos.fdc3.schema.SchemaConverter; + +/** + * Interface for messaging between the app and the Desktop Agent. + */ +public interface Messaging { + + /** + * Creates UUIDs used in outgoing messages. + * + * @return a new UUID string + */ + String createUUID(); + + /** + * Post an outgoing message. + * + * @param message the message to send + * @return a CompletionStage that completes when the message is sent + */ + CompletionStage post(Map message); + + /** + * Registers a listener for incoming messages. + * + * @param listener the listener to register + */ + void register(RegisterableListener listener); + + /** + * Unregister a listener with the given id. + * + * @param id the listener id + */ + void unregister(String id); + + /** + * Create a metadata element to attach to outgoing messages. + * + * @return the metadata object + */ + AddContextListenerRequestMeta createMeta(); + + /** + * Waits for a specific matching message. + * + * @param the expected response type + * @param filter predicate to match the expected message + * @param timeoutMs timeout in milliseconds + * @param timeoutErrorMessage error message if timeout occurs + * @return a CompletionStage containing the matched message + */ + CompletionStage waitFor(Predicate filter, long timeoutMs, String timeoutErrorMessage); + + /** + * Sends a request message and waits for a response. + * If the response contains a payload.error, it is thrown. + * + * @param the expected response type + * @param message the request message to send + * @param expectedTypeName the expected response type name + * @param timeoutMs timeout in milliseconds + * @return a CompletionStage containing the response + */ + CompletionStage exchange(Map message, String expectedTypeName, long timeoutMs); + + /** + * App identification used to provide source information used in + * message meta elements, IntentResolution etc. + * + * @return the app identifier + */ + AppIdentifier getAppIdentifier(); + + /** + * Disconnects the underlying message transport. + * + * @return a CompletionStage that completes when disconnected + */ + CompletionStage disconnect(); + + /** + * Get the schema converter for converting between JSON and FDC3 message types. + * + * @return the SchemaConverter instance + */ + SchemaConverter getConverter(); +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/AppSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/AppSupport.java new file mode 100644 index 00000000..4bf4e0b5 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/AppSupport.java @@ -0,0 +1,68 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.apps; + +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.api.types.AppIdentifier; + +/** + * Interface for application-related operations. + */ +public interface AppSupport { + + /** + * Find instances of an application. + * + * @param app the application identifier + * @return a CompletionStage containing the list of app instances + */ + CompletionStage> findInstances(AppIdentifier app); + + /** + * Get metadata for an application. + * + * @param app the application identifier + * @return a CompletionStage containing the app metadata + */ + CompletionStage getAppMetadata(AppIdentifier app); + + /** + * Open an application. + * + * @param app the application identifier + * @param context optional context to pass + * @param metadata optional app-provided metadata + * @return a CompletionStage containing the opened app identifier + */ + CompletionStage open( + AppIdentifier app, Context context, AppProvidableContextMetadata metadata); + + /** + * Get implementation metadata for the Desktop Agent. + * + * @return a CompletionStage containing the implementation metadata + */ + CompletionStage getImplementationMetadata(); + + CompletionStage close(); +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/DefaultAppSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/DefaultAppSupport.java new file mode 100644 index 00000000..ba1ccc72 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/apps/DefaultAppSupport.java @@ -0,0 +1,216 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.apps; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.errors.OpenError; +import org.finos.fdc3.api.errors.ResolveError; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.util.ThrowIfUndefined; +import org.finos.fdc3.schema.*; + +/** + * Default implementation of AppSupport. + */ +public class DefaultAppSupport implements AppSupport { + + private final Messaging messaging; + private final long messageExchangeTimeout; + private final long appLaunchTimeout; + + public DefaultAppSupport(Messaging messaging, long messageExchangeTimeout, long appLaunchTimeout) { + this.messaging = messaging; + this.messageExchangeTimeout = messageExchangeTimeout; + this.appLaunchTimeout = appLaunchTimeout; + } + + @Override + public CompletionStage> findInstances(AppIdentifier app) { + // Build typed request + FindInstancesRequest request = new FindInstancesRequest(); + request.setType(FindInstancesRequestType.FIND_INSTANCES_REQUEST); + request.setMeta(messaging.createMeta()); + + FindInstancesRequestPayload payload = new FindInstancesRequestPayload(); + payload.setApp(app); + request.setPayload(payload); + + // Convert to Map for messaging + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "findInstancesResponse", messageExchangeTimeout) + .thenApply(response -> { + FindInstancesResponse typedResponse = messaging.getConverter() + .convertValue(response, FindInstancesResponse.class); + + if (typedResponse.getPayload() == null || + typedResponse.getPayload().getAppIdentifiers() == null) { + return new ArrayList<>(); + } + + // AppMetadata extends AppIdentifier, so we can return directly + return typedResponse.getPayload().getAppIdentifiers().stream() + .map(am -> (AppIdentifier) am) + .collect(Collectors.toList()); + }); + } + + @Override + public CompletionStage getAppMetadata(AppIdentifier app) { + // Build typed request + GetAppMetadataRequest request = new GetAppMetadataRequest(); + request.setType(GetAppMetadataRequestType.GET_APP_METADATA_REQUEST); + request.setMeta(messaging.createMeta()); + + GetAppMetadataRequestPayload payload = new GetAppMetadataRequestPayload(); + payload.setApp(app); + request.setPayload(payload); + + // Convert to Map for messaging + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getAppMetadataResponse", messageExchangeTimeout) + .thenApply(response -> { + GetAppMetadataResponse typedResponse = messaging.getConverter() + .convertValue(response, GetAppMetadataResponse.class); + + ThrowIfUndefined.throwIfUndefined( + typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getAppMetadata(), + "Invalid response from Desktop Agent to getAppMetadata!", + response, + ResolveError.TargetAppUnavailable.toString()); + + // Schema now uses fdc3-standard AppMetadata directly + return typedResponse.getPayload().getAppMetadata(); + }); + } + + @Override + public CompletionStage open( + AppIdentifier app, Context context, AppProvidableContextMetadata metadata) { + OpenRequest request = new OpenRequest(); + request.setType(OpenRequestType.OPEN_REQUEST); + request.setMeta(messaging.createMeta()); + + OpenRequestPayload payload = new OpenRequestPayload(); + payload.setApp(app); + if (context != null) { + payload.setContext(context); + } + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + @SuppressWarnings("unchecked") + Map payloadMap = (Map) requestMap.get("payload"); + if (payloadMap != null && metadata != null) { + payloadMap.put("metadata", ContextMetadataMapper.toWire(metadata)); + } else if (payloadMap != null) { + payloadMap.remove("metadata"); + } + + return messaging.>exchange(requestMap, "openResponse", appLaunchTimeout) + .thenApply(response -> { + OpenResponse typedResponse = messaging.getConverter() + .convertValue(response, OpenResponse.class); + + ThrowIfUndefined.throwIfUndefined( + typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getAppIdentifier(), + "Invalid response from Desktop Agent to open!", + response, + OpenError.AppNotFound.toString()); + + return typedResponse.getPayload().getAppIdentifier(); + }); + } + + @Override + public CompletionStage close() { + Map request = new HashMap<>(); + request.put("type", "closeRequest"); + request.put("meta", messaging.getConverter().toMap(messaging.createMeta())); + request.put("payload", new HashMap<>()); + + return messaging.>exchange(request, "closeResponse", messageExchangeTimeout) + .thenApply(response -> null); + } + + @Override + public CompletionStage getImplementationMetadata() { + // Build typed request + GetInfoRequest request = new GetInfoRequest(); + request.setType(GetInfoRequestType.GET_INFO_REQUEST); + request.setMeta(messaging.createMeta()); + request.setPayload(new GetInfoRequestPayload()); + + // Convert to Map for messaging + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getInfoResponse", messageExchangeTimeout) + .thenApply(response -> { + GetInfoResponse typedResponse = messaging.getConverter() + .convertValue(response, GetInfoResponse.class); + + if (typedResponse.getPayload() != null && + typedResponse.getPayload().getImplementationMetadata() != null) { + // Schema now uses fdc3-standard ImplementationMetadata directly + ImplementationMetadata metadata = typedResponse.getPayload().getImplementationMetadata(); + + return metadata; + } else { + Logger.error("Invalid response from Desktop Agent to getInfo!"); + return createUnknownImplementationMetadata(); + } + }); + } + + // ============ Conversion helpers ============ + // Schema now uses fdc3-standard AppIdentifier directly, no conversion needed + + private ImplementationMetadata createUnknownImplementationMetadata() { + ImplementationMetadata result = new ImplementationMetadata(); + result.setFdc3Version("unknown"); + result.setProvider("unknown"); + + AppMetadata appMetadata = new AppMetadata(); + appMetadata.setAppId("unknown"); + appMetadata.setInstanceId("unknown"); + result.setAppMetadata(appMetadata); + + ImplementationMetadata.OptionalFeatures optFeatures = new ImplementationMetadata.OptionalFeatures(); + result.setOptionalFeatures(optFeatures); + + return result; + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/ChannelSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/ChannelSupport.java new file mode 100644 index 00000000..dbf0c133 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/ChannelSupport.java @@ -0,0 +1,95 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.Listener; + +/** + * Interface for channel-related operations. + */ +public interface ChannelSupport { + + /** + * Get the current user channel. + * + * @return a CompletionStage containing the current channel, or null if not joined + */ + CompletionStage getUserChannel(); + + /** + * Get all available user channels. + * + * @return a CompletionStage containing the list of user channels + */ + CompletionStage> getUserChannels(); + + /** + * Get or create an app channel with the specified ID. + * + * @param id the channel ID + * @return a CompletionStage containing the channel + */ + CompletionStage getOrCreate(String id); + + /** + * Create a new private channel. + * + * @return a CompletionStage containing the new private channel + */ + CompletionStage createPrivateChannel(); + + /** + * Leave the current user channel. + * + * @return a CompletionStage that completes when left + */ + CompletionStage leaveUserChannel(); + + /** + * Join a user channel by ID. + * + * @param id the channel ID to join + * @return a CompletionStage that completes when joined + */ + CompletionStage joinUserChannel(String id); + + /** + * Add a context listener. + * + * @param handler the context handler + * @param contextTypes types to listen for, or {@code null} for all types + * @return a CompletionStage containing the listener + */ + CompletionStage addContextListener(ContextHandler handler, List contextTypes); + + /** + * Add an event listener. + * + * @param handler the event handler + * @param type the event type to listen for, or null for all types + * @return a CompletionStage containing the listener + */ + CompletionStage addEventListener(EventHandler handler, String type); +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannel.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannel.java new file mode 100644 index 00000000..f8dade4d --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannel.java @@ -0,0 +1,313 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DisplayMetadata; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.ContextWithMetadata; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.api.errors.ChannelError; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.finos.fdc3.proxy.listeners.ChannelEventListener; +import org.finos.fdc3.proxy.listeners.DefaultContextListener; +import org.finos.fdc3.schema.*; + +/** + * Default implementation of a Channel. + */ +@JsonAutoDetect( + getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE, + fieldVisibility = JsonAutoDetect.Visibility.NONE, + setterVisibility = JsonAutoDetect.Visibility.NONE, + creatorVisibility = JsonAutoDetect.Visibility.NONE) +public class DefaultChannel implements Channel { + + @JsonIgnore + protected final Messaging messaging; + @JsonIgnore + protected final long messageExchangeTimeout; + private final String id; + private final Type type; + @JsonIgnore + private final DisplayMetadata displayMetadata; + + public DefaultChannel( + Messaging messaging, + long messageExchangeTimeout, + String id, + Type type, + DisplayMetadata displayMetadata) { + this.messaging = messaging; + this.messageExchangeTimeout = messageExchangeTimeout; + this.id = id; + this.type = type; + this.displayMetadata = displayMetadata; + } + + @Override + @JsonProperty("id") + public String getId() { + return id; + } + + @Override + @JsonIgnore + public Type getType() { + return type; + } + + @JsonProperty("type") + @JsonGetter("type") + public String getTypeValue() { + return type != null ? type.getValue() : null; + } + + @Override + @JsonProperty("displayMetadata") + public DisplayMetadata getDisplayMetadata() { + return displayMetadata; + } + + @Override + @JsonIgnore + public CompletionStage broadcast(Context context) { + return broadcast(context, null); + } + + @Override + @JsonIgnore + public CompletionStage broadcast(Context context, AppProvidableContextMetadata metadata) { + if (context == null || context.getType() == null) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.MalformedContext.toString())); + } + + BroadcastRequest request = new BroadcastRequest(); + request.setType(BroadcastRequestType.BROADCAST_REQUEST); + request.setMeta(messaging.createMeta()); + + BroadcastRequestPayload payload = new BroadcastRequestPayload(); + payload.setChannelID(id); + payload.setContext(context); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + @SuppressWarnings("unchecked") + Map payloadMap = (Map) requestMap.get("payload"); + if (payloadMap != null && metadata != null) { + payloadMap.put("metadata", ContextMetadataMapper.toWire(metadata)); + } else if (payloadMap != null) { + payloadMap.remove("metadata"); + } + + return messaging.>exchange(requestMap, "broadcastResponse", messageExchangeTimeout) + .thenApply(response -> null); + } + + @Override + @JsonIgnore + public CompletionStage> getCurrentContext() { + return getCurrentContext(null); + } + + @Override + @JsonIgnore + public CompletionStage> getCurrentContext(String contextType) { + GetCurrentContextRequest request = new GetCurrentContextRequest(); + request.setType(GetCurrentContextRequestType.GET_CURRENT_CONTEXT_REQUEST); + request.setMeta(messaging.createMeta()); + + GetCurrentContextRequestPayload payload = new GetCurrentContextRequestPayload(); + payload.setChannelID(id); + payload.setContextType(contextType); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getCurrentContextResponse", messageExchangeTimeout) + .thenApply(response -> { + ContextWithMetadata parsed = parseCurrentContextResponse(response); + return parsed != null ? Optional.of(parsed.getContext()) : Optional.empty(); + }); + } + + @Override + @JsonIgnore + public CompletionStage> getCurrentContextWithMetadata(String contextType) { + GetCurrentContextRequest request = new GetCurrentContextRequest(); + request.setType(GetCurrentContextRequestType.GET_CURRENT_CONTEXT_REQUEST); + request.setMeta(messaging.createMeta()); + + GetCurrentContextRequestPayload payload = new GetCurrentContextRequestPayload(); + payload.setChannelID(id); + payload.setContextType(contextType); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getCurrentContextResponse", messageExchangeTimeout) + .thenApply(response -> Optional.ofNullable(parseCurrentContextResponse(response))); + } + + @Override + @JsonIgnore + public CompletionStage clearContext(String contextType) { + ClearContextRequest request = new ClearContextRequest(); + request.setType(ClearContextRequestType.CLEAR_CONTEXT_REQUEST); + request.setMeta(messaging.createMeta()); + + ClearContextRequestPayload payload = new ClearContextRequestPayload(); + payload.setChannelID(id); + payload.setContextType(contextType); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "clearContextResponse", messageExchangeTimeout) + .thenApply(response -> null); + } + + @Override + @JsonIgnore + public CompletionStage addContextListener(String contextType, ContextHandler handler) { + if (handler == null) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + List types = contextType == null ? null : List.of(contextType); + return addContextListenerInner(types, handler); + } + + @Override + @JsonIgnore + public CompletionStage addContextListener(List contextTypes, ContextHandler handler) { + // null is the String-overload "all types" signal; reflective callers cannot + // distinguish the overloads, so treat null here the same way. + if (contextTypes == null) { + return addContextListener((String) null, handler); + } + if (handler == null || contextTypes.isEmpty() || contextTypes.stream().anyMatch(t -> t == null)) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + return addContextListenerInner(contextTypes, handler); + } + + protected CompletionStage addContextListenerInner( + List contextTypes, ContextHandler handler) { + DefaultContextListener listener = new DefaultContextListener( + messaging, + messageExchangeTimeout, + id, + contextTypes, + handler + ); + return listener.register().thenApply(v -> listener); + } + + @Override + public CompletionStage addEventListener(String type, EventHandler handler) { + if (type != null) { + try { + if (FDC3Event.Type.fromValue(type) != FDC3Event.Type.CONTEXT_CLEARED) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + } catch (IllegalArgumentException e) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + } + ChannelEventListener listener = new ChannelEventListener( + messaging, messageExchangeTimeout, type, id, handler); + return listener.register().thenApply(v -> listener); + } + + /** + * Parses a getCurrentContextResponse payload, mirroring TypeScript + * {@code parseCurrentContextResponse}. + */ + @SuppressWarnings("unchecked") + private ContextWithMetadata parseCurrentContextResponse(Map response) { + Map responsePayload = (Map) response.get("payload"); + if (responsePayload == null) { + throw new RuntimeException(ChannelError.MalformedContext.toString()); + } + + boolean hasContextKey = responsePayload.containsKey("context"); + Object ctxRaw = responsePayload.get("context"); + boolean hasMetadataKey = responsePayload.containsKey("metadata"); + Object metadataRaw = responsePayload.get("metadata"); + + if (ctxRaw == null) { + if (!hasContextKey) { + // missing context key — MalformedContext (TS: context === undefined) + throw new RuntimeException(ChannelError.MalformedContext.toString()); + } + // context explicitly null: only valid when metadata is also explicitly null + // (TS treats absent metadata as undefined, which is !== null → MalformedContext) + if (!hasMetadataKey || metadataRaw != null) { + throw new RuntimeException(ChannelError.MalformedContext.toString()); + } + return null; + } + + if (!hasMetadataKey || metadataRaw == null) { + throw new RuntimeException(ChannelError.MalformedContext.toString()); + } + + Context context; + if (ctxRaw instanceof Context) { + context = (Context) ctxRaw; + } else if (ctxRaw instanceof Map) { + context = Context.fromMap((Map) ctxRaw); + } else { + throw new RuntimeException(ChannelError.MalformedContext.toString()); + } + + GetCurrentContextResponse typedResponse = messaging.getConverter() + .convertValue(response, GetCurrentContextResponse.class); + Map payloadMetadata = metadataRaw instanceof Map + ? (Map) metadataRaw + : null; + Object messageTimestamp = typedResponse.getMeta() != null + ? typedResponse.getMeta().getTimestamp() + : null; + ContextMetadata metadata = ContextMetadataMapper.fromWire( + payloadMetadata, messageTimestamp, ContextMetadataMapper.MissingTraceId.EMPTY); + return new ContextWithMetadata(context, metadata); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannelSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannelSupport.java new file mode 100644 index 00000000..bd8742e9 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultChannelSupport.java @@ -0,0 +1,428 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.errors.ChannelError; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.api.ui.ChannelSelector; +import org.finos.fdc3.api.ui.Connectable; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.listeners.DesktopAgentEventListener; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.util.ThrowIfUndefined; +import org.finos.fdc3.schema.CreatePrivateChannelRequest; +import org.finos.fdc3.schema.CreatePrivateChannelRequestPayload; +import org.finos.fdc3.schema.CreatePrivateChannelRequestType; +import org.finos.fdc3.schema.CreatePrivateChannelResponse; +import org.finos.fdc3.schema.GetCurrentChannelRequest; +import org.finos.fdc3.schema.GetCurrentChannelRequestPayload; +import org.finos.fdc3.schema.GetCurrentChannelRequestType; +import org.finos.fdc3.schema.GetCurrentChannelResponse; +import org.finos.fdc3.schema.GetOrCreateChannelRequest; +import org.finos.fdc3.schema.GetOrCreateChannelRequestPayload; +import org.finos.fdc3.schema.GetOrCreateChannelRequestType; +import org.finos.fdc3.schema.GetOrCreateChannelResponse; +import org.finos.fdc3.schema.GetUserChannelsRequest; +import org.finos.fdc3.schema.GetUserChannelsRequestPayload; +import org.finos.fdc3.schema.GetUserChannelsRequestType; +import org.finos.fdc3.schema.GetUserChannelsResponse; +import org.finos.fdc3.schema.JoinUserChannelRequest; +import org.finos.fdc3.schema.JoinUserChannelRequestPayload; +import org.finos.fdc3.schema.JoinUserChannelRequestType; +import org.finos.fdc3.schema.LeaveCurrentChannelRequest; +import org.finos.fdc3.schema.LeaveCurrentChannelRequestPayload; +import org.finos.fdc3.schema.LeaveCurrentChannelRequestType; + +/** + * Default implementation of ChannelSupport. + */ +public class DefaultChannelSupport implements ChannelSupport, Connectable { + + private final Messaging messaging; + private final ChannelSelector channelSelector; + private final long messageExchangeTimeout; + private List userChannels = null; + private Channel currentChannel = null; + /** + * Mutated on caller threads and iterated on the WebSocket receive thread, so it has to be + * safe for concurrent traversal. + */ + private final List userChannelListeners = new CopyOnWriteArrayList<>(); + private boolean userChannelChangedListenerRegistered = false; + + public DefaultChannelSupport(Messaging messaging, ChannelSelector channelSelector, long messageExchangeTimeout) { + this.messaging = messaging; + this.channelSelector = channelSelector; + this.messageExchangeTimeout = messageExchangeTimeout; + + // Set up channel change callback + channelSelector.setChannelChangeCallback(channelId -> { + Logger.debug("Channel selector reports channel changed: {}", channelId); + CompletionStage change = channelId == null + ? leaveUserChannel() + : joinUserChannel(channelId); + // The selector callback returns nothing, so log rather than discard the failure. + change.exceptionally(error -> { + Logger.error("Failed to change user channel to {} on behalf of the channel selector", + channelId, error); + return null; + }); + }); + } + + @Override + public CompletionStage connect() { + CompletionStage loadChannel = getUserChannel().thenApply(channel -> { + currentChannel = channel; + return null; + }); + if (userChannelChangedListenerRegistered) { + return loadChannel; + } + userChannelChangedListenerRegistered = true; + return loadChannel.thenCompose(v -> registerUserChannelChangedListener()); + } + + /** + * Update cached user channel synchronously from a channel id (e.g. from userChannelChanged). + * Must run before any await in event handlers so other listeners calling getCurrentChannel() + * do not read a stale channel. + */ + private void applyCurrentChannelFromId(String channelId) { + if (channelId == null) { + currentChannel = null; + return; + } + if (userChannels != null) { + Channel cached = userChannels.stream() + .filter(c -> channelId.equals(c.getId())) + .findFirst() + .orElse(null); + if (cached != null) { + currentChannel = cached; + } else if (currentChannel == null || !channelId.equals(currentChannel.getId())) { + currentChannel = null; + } + } else if (currentChannel == null || !channelId.equals(currentChannel.getId())) { + currentChannel = null; + } + } + + private CompletionStage registerUserChannelChangedListener() { + return addEventListener(event -> { + @SuppressWarnings("unchecked") + Map details = (Map) event.getDetails(); + String newChannelId = details != null ? (String) details.get("currentChannelId") : null; + Logger.debug("Desktop Agent reports channel changed: {}", newChannelId); + + applyCurrentChannelFromId(newChannelId); + + Channel theChannel = currentChannel; + CompletionStage resolveChannel; + if (newChannelId != null && theChannel == null) { + resolveChannel = getUserChannels().thenApply(channels -> channels.stream() + .filter(c -> newChannelId.equals(c.getId())) + .findFirst() + .orElse(null)); + } else { + resolveChannel = CompletableFuture.completedFuture(theChannel); + } + + resolveChannel.thenCompose(channel -> { + if (newChannelId != null && channel == null) { + Logger.warn( + "Received user channel update with unknown user channel (user channel listeners will not work): {}", + newChannelId); + } + currentChannel = channel; + return getUserChannelsCached(); + }).thenCompose(channels -> { + channelSelector.updateChannel(currentChannel != null ? currentChannel.getId() : null, channels); + CompletionStage notify = CompletableFuture.completedFuture(null); + for (UserChannelContextListener listener : userChannelListeners) { + notify = notify.thenCompose(v -> listener.changeChannel()); + } + return notify; + }).exceptionally(error -> { + // This chain is not returned to anyone, so without this the failure would be + // discarded and the channel change would appear to have succeeded. + Logger.error("Failed to apply user channel change to {}", newChannelId, error); + return null; + }); + }, "userChannelChanged").thenApply(listener -> null); + } + + @Override + public CompletionStage disconnect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage addEventListener(EventHandler handler, String type) { + DesktopAgentEventListener listener; + try { + listener = new DesktopAgentEventListener( + messaging, messageExchangeTimeout, type, handler); + } catch (RuntimeException e) { + // The constructor rejects unsupported event types. Surface that as a rejected stage. + return CompletableFuture.failedFuture(e); + } + return listener.register().thenApply(v -> listener); + } + + @Override + public CompletionStage getUserChannel() { + if (currentChannel != null) { + return CompletableFuture.completedFuture(currentChannel); + } + + GetCurrentChannelRequest request = new GetCurrentChannelRequest(); + request.setType(GetCurrentChannelRequestType.GET_CURRENT_CHANNEL_REQUEST); + request.setMeta(messaging.createMeta()); + request.setPayload(new GetCurrentChannelRequestPayload()); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getCurrentChannelResponse", messageExchangeTimeout) + .thenApply(response -> { + // Checked against the raw payload rather than the converted object, because + // conversion collapses "channel was omitted" and "channel was null" into the + // same Java null. The standard requires an explicit null when the app is not + // joined to a channel, so only the omission is a Desktop Agent fault. + @SuppressWarnings("unchecked") + Map rawPayload = (Map) response.get("payload"); + ThrowIfUndefined.throwIfUndefined( + rawPayload == null || rawPayload.containsKey("channel") ? Boolean.TRUE : null, + "Invalid response from Desktop Agent to getCurrentChannel " + + "(channel should be explicitly null if no channel is set)!", + response, + ChannelError.NoChannelFound.toString()); + + GetCurrentChannelResponse typedResponse = messaging.getConverter() + .convertValue(response, GetCurrentChannelResponse.class); + + if (typedResponse.getPayload() == null || + typedResponse.getPayload().getChannel() == null) { + return null; + } + + org.finos.fdc3.schema.Channel schemaChannel = typedResponse.getPayload().getChannel(); + // Schema now uses fdc3-standard DisplayMetadata directly + return new DefaultChannel(messaging, messageExchangeTimeout, + schemaChannel.getID(), Channel.Type.User, schemaChannel.getDisplayMetadata()); + }); + } + + private CompletionStage> getUserChannelsCached() { + if (userChannels != null) { + return CompletableFuture.completedFuture(userChannels); + } + return getUserChannels(); + } + + @Override + public CompletionStage> getUserChannels() { + GetUserChannelsRequest request = new GetUserChannelsRequest(); + request.setType(GetUserChannelsRequestType.GET_USER_CHANNELS_REQUEST); + request.setMeta(messaging.createMeta()); + request.setPayload(new GetUserChannelsRequestPayload()); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getUserChannelsResponse", messageExchangeTimeout) + .thenApply(response -> { + GetUserChannelsResponse typedResponse = messaging.getConverter() + .convertValue(response, GetUserChannelsResponse.class); + + if (typedResponse.getPayload() == null || + typedResponse.getPayload().getUserChannels() == null) { + userChannels = new ArrayList<>(); + return userChannels; + } + + // Schema now uses fdc3-standard DisplayMetadata directly + userChannels = typedResponse.getPayload().getUserChannels().stream() + .map(c -> (Channel) new DefaultChannel( + messaging, messageExchangeTimeout, c.getID(), Channel.Type.User, + c.getDisplayMetadata())) + .collect(Collectors.toList()); + + return userChannels; + }); + } + + @Override + public CompletionStage getOrCreate(String id) { + if (id == null || id.trim().isEmpty()) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + + GetOrCreateChannelRequest request = new GetOrCreateChannelRequest(); + request.setType(GetOrCreateChannelRequestType.GET_OR_CREATE_CHANNEL_REQUEST); + request.setMeta(messaging.createMeta()); + + GetOrCreateChannelRequestPayload payload = new GetOrCreateChannelRequestPayload(); + payload.setChannelID(id); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "getOrCreateChannelResponse", messageExchangeTimeout) + .thenApply(response -> { + GetOrCreateChannelResponse typedResponse = messaging.getConverter() + .convertValue(response, GetOrCreateChannelResponse.class); + + ThrowIfUndefined.throwIfUndefined( + typedResponse.getPayload() == null ? null : typedResponse.getPayload().getChannel(), + "Invalid response from Desktop Agent to getOrCreate!", + response, + ChannelError.CreationFailed.toString()); + + org.finos.fdc3.schema.Channel schemaChannel = typedResponse.getPayload().getChannel(); + // Schema now uses fdc3-standard DisplayMetadata directly + return new DefaultChannel(messaging, messageExchangeTimeout, id, Channel.Type.App, + schemaChannel.getDisplayMetadata()); + }); + } + + @Override + public CompletionStage createPrivateChannel() { + CreatePrivateChannelRequest request = new CreatePrivateChannelRequest(); + request.setType(CreatePrivateChannelRequestType.CREATE_PRIVATE_CHANNEL_REQUEST); + request.setMeta(messaging.createMeta()); + request.setPayload(new CreatePrivateChannelRequestPayload()); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging + .>exchange(requestMap, "createPrivateChannelResponse", messageExchangeTimeout) + .thenApply(response -> { + CreatePrivateChannelResponse typedResponse = messaging.getConverter() + .convertValue(response, CreatePrivateChannelResponse.class); + + ThrowIfUndefined.throwIfUndefined( + typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getPrivateChannel(), + "Invalid response from Desktop Agent to createPrivateChannel!", + response, + ChannelError.CreationFailed.toString()); + + String id = typedResponse.getPayload().getPrivateChannel().getID(); + return new DefaultPrivateChannel(messaging, messageExchangeTimeout, id); + }); + } + + @Override + public CompletionStage leaveUserChannel() { + LeaveCurrentChannelRequest request = new LeaveCurrentChannelRequest(); + request.setType(LeaveCurrentChannelRequestType.LEAVE_CURRENT_CHANNEL_REQUEST); + request.setMeta(messaging.createMeta()); + request.setPayload(new LeaveCurrentChannelRequestPayload()); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging + .>exchange(requestMap, "leaveCurrentChannelResponse", messageExchangeTimeout) + .thenCompose(response -> { + currentChannel = null; + return getUserChannelsCached().thenAccept(channels -> { + channelSelector.updateChannel(null, channels); + }); + }); + } + + @Override + public CompletionStage joinUserChannel(String id) { + JoinUserChannelRequest request = new JoinUserChannelRequest(); + request.setType(JoinUserChannelRequestType.JOIN_USER_CHANNEL_REQUEST); + request.setMeta(messaging.createMeta()); + + JoinUserChannelRequestPayload payload = new JoinUserChannelRequestPayload(); + payload.setChannelID(id); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "joinUserChannelResponse", messageExchangeTimeout) + .thenCompose(response -> getUserChannelsCached()) + .thenCompose(channels -> { + currentChannel = channels.stream() + .filter(c -> id.equals(c.getId())) + .findFirst() + .orElse(null); + + if (currentChannel == null) { + throw new RuntimeException(ChannelError.NoChannelFound.toString()); + } + + channelSelector.updateChannel(id, channels); + + CompletionStage notify = CompletableFuture.completedFuture(null); + for (UserChannelContextListener listener : userChannelListeners) { + notify = notify.thenCompose(v -> listener.changeChannel()); + } + return notify; + }); + } + + @Override + public CompletionStage addContextListener(ContextHandler handler, List contextTypes) { + if (handler == null) { + return CompletableFuture.failedFuture( + new RuntimeException("Invalid arguments passed to addContextListener!")); + } + if (contextTypes != null && contextTypes.isEmpty()) { + return CompletableFuture.failedFuture( + new RuntimeException("Empty array passed to addContextListener")); + } + if (contextTypes != null && contextTypes.stream().anyMatch(t -> t == null)) { + return CompletableFuture.failedFuture( + new RuntimeException( + "Invalid arguments passed to addContextListener: array must contain only strings")); + } + DefaultUserChannelContextListener listener = new DefaultUserChannelContextListener( + this, messaging, messageExchangeTimeout, contextTypes, handler); + userChannelListeners.add(listener); + return listener.register().thenApply(v -> listener); + } + + // Package-private for UserChannelContextListener access + Channel getCurrentChannelInternal() { + return currentChannel; + } + + // Package-private for UserChannelContextListener to remove itself on + // unsubscribe + void removeUserChannelListener(UserChannelContextListener listener) { + userChannelListeners.remove(listener); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultPrivateChannel.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultPrivateChannel.java new file mode 100644 index 00000000..5bff9c23 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultPrivateChannel.java @@ -0,0 +1,137 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.errors.ChannelError; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.listeners.AbstractPrivateChannelEventListener; +import org.finos.fdc3.proxy.listeners.DefaultContextListener; +import org.finos.fdc3.proxy.listeners.PrivateChannelAddContextEventListener; +import org.finos.fdc3.proxy.listeners.PrivateChannelDisconnectEventListener; +import org.finos.fdc3.proxy.listeners.PrivateChannelNullEventListener; +import org.finos.fdc3.proxy.listeners.PrivateChannelUnsubscribeEventListener; +import org.finos.fdc3.schema.*; + +/** + * Default implementation of a PrivateChannel. + */ +public class DefaultPrivateChannel extends DefaultChannel implements PrivateChannel { + + public DefaultPrivateChannel(Messaging messaging, long messageExchangeTimeout, String id) { + super(messaging, messageExchangeTimeout, id, Channel.Type.Private, null); + } + + @Override + public CompletionStage addEventListener(String type, EventHandler handler) { + if (FDC3Event.Type.CONTEXT_CLEARED.getValue().equals(type)) { + return super.addEventListener(type, handler); + } + + if (type == null) { + return addAllEventListener(handler); + } + + AbstractPrivateChannelEventListener listener; + try { + switch (FDC3Event.Type.fromValue(type)) { + case ADD_CONTEXT_LISTENER: + listener = new PrivateChannelAddContextEventListener(messaging, messageExchangeTimeout, getId(), handler); + break; + case ON_UNSUBSCRIBE: + listener = new PrivateChannelUnsubscribeEventListener(messaging, messageExchangeTimeout, getId(), handler); + break; + case ON_DISCONNECT: + listener = new PrivateChannelDisconnectEventListener(messaging, messageExchangeTimeout, getId(), handler); + break; + default: + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + } catch (IllegalArgumentException e) { + return CompletableFuture.failedFuture( + new RuntimeException(ChannelError.InvalidArguments.toString())); + } + + return listener.register().thenApply(v -> listener); + } + + private CompletionStage addAllEventListener(EventHandler handler) { + return super.addEventListener(FDC3Event.Type.CONTEXT_CLEARED.getValue(), handler).thenCompose(channelListener -> { + PrivateChannelNullEventListener privateChannelListener = new PrivateChannelNullEventListener( + messaging, messageExchangeTimeout, getId(), handler); + return privateChannelListener.register() + .thenApply(v -> (Listener) new Listener() { + @Override + public CompletionStage unsubscribe() { + return channelListener.unsubscribe() + .thenCompose(ignored -> privateChannelListener.unsubscribe()); + } + }) + .handle((listener, ex) -> { + if (ex == null) { + return CompletableFuture.completedFuture(listener); + } + return channelListener.unsubscribe().thenCompose(ignored -> { + CompletableFuture failed = new CompletableFuture<>(); + failed.completeExceptionally(ex); + return failed; + }); + }) + .thenCompose(stage -> stage); + }); + } + + @Override + public CompletionStage disconnect() { + PrivateChannelDisconnectRequest request = new PrivateChannelDisconnectRequest(); + request.setType(PrivateChannelDisconnectRequestType.PRIVATE_CHANNEL_DISCONNECT_REQUEST); + request.setMeta(messaging.createMeta()); + + PrivateChannelDisconnectRequestPayload payload = new PrivateChannelDisconnectRequestPayload(); + payload.setChannelID(getId()); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "privateChannelDisconnectResponse", messageExchangeTimeout) + .thenApply(response -> null); + } + + @Override + protected CompletionStage addContextListenerInner( + List contextTypes, ContextHandler handler) { + DefaultContextListener listener = new DefaultContextListener( + messaging, + messageExchangeTimeout, + getId(), + contextTypes, + handler + ); + return listener.register().thenApply(v -> listener); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultUserChannelContextListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultUserChannelContextListener.java new file mode 100644 index 00000000..701b8385 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/DefaultUserChannelContextListener.java @@ -0,0 +1,103 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.listeners.DefaultContextListener; + +/** + * Context listener that tracks user channel changes. + * This extends DefaultContextListener and adds support for changing channels + * when the user changes their current user channel. + */ +public class DefaultUserChannelContextListener extends DefaultContextListener implements UserChannelContextListener { + + private final DefaultChannelSupport channelSupport; + + public DefaultUserChannelContextListener( + DefaultChannelSupport channelSupport, + Messaging messaging, + long messageExchangeTimeout, + List contextTypes, + ContextHandler handler) { + super(messaging, messageExchangeTimeout, null, contextTypes, handler, "broadcastEvent"); + this.channelSupport = channelSupport; + } + + @Override + public CompletionStage register() { + return super.register().thenCompose(v -> changeChannel()); + } + + /** + * Called when the user channel changes. Gets the current context from the + * current channel and notifies the handler if there is one. + */ + @Override + public CompletionStage changeChannel() { + Channel currentChannel = channelSupport.getCurrentChannelInternal(); + if (currentChannel == null) { + return CompletableFuture.completedFuture(null); + } + return replayCurrentContext(currentChannel); + } + + @Override + public CompletionStage unsubscribe() { + channelSupport.removeUserChannelListener(this); + return super.unsubscribe(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + String type = (String) message.get("type"); + if (!messageType.equals(type)) { + return false; + } + + Map payload = (Map) message.get("payload"); + if (payload == null) { + return false; + } + + // Check if on matching channel or open broadcast + String msgChannelId = (String) payload.get("channelId"); + Channel currentChannel = channelSupport.getCurrentChannelInternal(); + boolean onMatchingChannel = currentChannel != null && currentChannel.getId().equals(msgChannelId); + boolean openBroadcast = msgChannelId == null; + + if (!onMatchingChannel && !openBroadcast) { + return false; + } + + Map context = (Map) payload.get("context"); + if (context == null) { + return false; + } + + String msgContextType = (String) context.get("type"); + return matchesContextType(msgContextType); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/UserChannelContextListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/UserChannelContextListener.java new file mode 100644 index 00000000..3a702084 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/channels/UserChannelContextListener.java @@ -0,0 +1,36 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.channels; + +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.listeners.RegisterableListener; + +/** + * This is a special version of a ContextListener created when the user calls the + * fdc3.addContextListener method. In this scenario, the listener will respond to broadcasts + * on whatever is the current user channel. + */ +public interface UserChannelContextListener extends RegisterableListener { + + /** + * This method is called when the user channel changes. The listener should then + * call its handler with the latest piece of relevant channel state and start responding to + * events on the new channelId. + */ + CompletionStage changeChannel(); +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/DefaultHeartbeatSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/DefaultHeartbeatSupport.java new file mode 100644 index 00000000..b31f1729 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/DefaultHeartbeatSupport.java @@ -0,0 +1,139 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.heartbeat; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; + +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.listeners.RegisterableListener; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.schema.AddContextListenerRequestMeta; +import org.finos.fdc3.schema.HeartbeatAcknowledgementRequest; +import org.finos.fdc3.schema.HeartbeatAcknowledgementRequestPayload; +import org.finos.fdc3.schema.HeartbeatAcknowledgementRequestType; + +/** + * Default implementation of HeartbeatSupport. + */ +public class DefaultHeartbeatSupport implements HeartbeatSupport { + + private final Messaging messaging; + private final long heartbeatIntervalMs; + private final ScheduledExecutorService scheduler; + private ScheduledFuture heartbeatTask; + private RegisterableListener heartbeatListener; + + public DefaultHeartbeatSupport(Messaging messaging, long heartbeatIntervalMs) { + this.messaging = messaging; + this.heartbeatIntervalMs = heartbeatIntervalMs; + this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "fdc3-heartbeat"); + t.setDaemon(true); + return t; + }); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage connect() { + // Register listener for heartbeat events + String id = messaging.createUUID(); + heartbeatListener = new RegisterableListener() { + @Override + public String getId() { + return id; + } + + @Override + public boolean filter(Map message) { + String type = (String) message.get("type"); + return "heartbeatEvent".equals(type); + } + + @Override + public void action(Map message) { + Map payload = (Map) message.get("payload"); + String timestamp = payload != null ? (String) payload.get("timestamp") : null; + Logger.debug("Received heartbeat at {}", timestamp); + + // Respond to heartbeat + respondToHeartbeat(message); + } + + @Override + public CompletionStage register() { + messaging.register(this); + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage unsubscribe() { + messaging.unregister(id); + return CompletableFuture.completedFuture(null); + } + }; + + messaging.register(heartbeatListener); + return CompletableFuture.completedFuture(null); + } + + @SuppressWarnings("unchecked") + private void respondToHeartbeat(Map heartbeatEvent) { + try { + Map meta = (Map) heartbeatEvent.get("meta"); + String eventUuid = meta != null ? (String) meta.get("eventUuid") : null; + + HeartbeatAcknowledgementRequest request = new HeartbeatAcknowledgementRequest(); + request.setType(HeartbeatAcknowledgementRequestType.HEARTBEAT_ACKNOWLEDGEMENT_REQUEST); + + AddContextListenerRequestMeta requestMeta = messaging.createMeta(); + // Set the requestUuid to match the eventUuid for correlation + if (eventUuid != null) { + requestMeta.setRequestUUID(eventUuid); + } + request.setMeta(requestMeta); + + HeartbeatAcknowledgementRequestPayload payload = new HeartbeatAcknowledgementRequestPayload(); + payload.setHeartbeatEventUUID(eventUuid); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + messaging.post(requestMap); + } catch (Exception e) { + Logger.error("Failed to respond to heartbeat", e); + } + } + + @Override + public CompletionStage disconnect() { + if (heartbeatTask != null) { + heartbeatTask.cancel(true); + } + if (heartbeatListener != null) { + messaging.unregister(heartbeatListener.getId()); + } + + scheduler.shutdown(); + return messaging.disconnect(); + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Nothing.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/HeartbeatSupport.java similarity index 62% rename from fdc3api/src/main/java/com/finos/fdc3/api/context/Nothing.java rename to fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/HeartbeatSupport.java index 700ee8dd..26b68c71 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Nothing.java +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/heartbeat/HeartbeatSupport.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,15 @@ * limitations under the License. */ -package com.finos.fdc3.api.context; +package org.finos.fdc3.proxy.heartbeat; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.finos.fdc3.api.ui.Connectable; -@JsonPropertyOrder({ - "type" -}) -public class Nothing extends Context { - public static String TYPE = "fdc3.nothing"; - - public Nothing() { - super(TYPE); - } +/** + * Interface for heartbeat support. + * Extends Connectable to allow connection management. + */ +public interface HeartbeatSupport extends Connectable { + // Heartbeat-specific methods can be added here if needed } + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentResolution.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentResolution.java new file mode 100644 index 00000000..7e2f7122 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentResolution.java @@ -0,0 +1,74 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.intents; + +import java.util.Optional; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.proxy.Messaging; + +/** + * Default implementation of IntentResolution. + */ +public class DefaultIntentResolution implements IntentResolution { + + private final Messaging messaging; + private final long messageExchangeTimeout; + private final CompletionStage resultPromise; + private final CompletionStage resultMetadataPromise; + private final AppIdentifier source; + private final String intent; + + public DefaultIntentResolution( + Messaging messaging, + long messageExchangeTimeout, + CompletionStage resultPromise, + CompletionStage resultMetadataPromise, + AppIdentifier source, + String intent) { + this.messaging = messaging; + this.messageExchangeTimeout = messageExchangeTimeout; + this.resultPromise = resultPromise; + this.resultMetadataPromise = resultMetadataPromise; + this.source = source; + this.intent = intent; + } + + @Override + public AppIdentifier getSource() { + return source; + } + + @Override + public String getIntent() { + return intent; + } + + @Override + public CompletionStage getResult() { + return resultPromise; + } + + @Override + public CompletionStage getResultMetadata() { + return resultMetadataPromise; + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentSupport.java new file mode 100644 index 00000000..3586507a --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/DefaultIntentSupport.java @@ -0,0 +1,476 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.intents; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.errors.ResolveError; +import org.finos.fdc3.api.errors.ResultError; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.api.ui.IntentResolver; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.channels.DefaultChannel; +import org.finos.fdc3.proxy.channels.DefaultPrivateChannel; +import org.finos.fdc3.proxy.listeners.DefaultIntentListener; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.finos.fdc3.proxy.util.ThrowIfUndefined; +import org.finos.fdc3.schema.*; + +/** + * Default implementation of IntentSupport. + */ +public class DefaultIntentSupport implements IntentSupport { + + private final Messaging messaging; + private final IntentResolver intentResolver; + private final long messageExchangeTimeout; + private final long appLaunchTimeout; + /** + * Mutated on caller threads and iterated on the WebSocket receive thread, so it has to be + * safe for concurrent traversal. + */ + private final List intentListeners = new CopyOnWriteArrayList<>(); + + /** Guards the check-then-add in {@link #registerIntentListener}. */ + private final Object intentListenerLock = new Object(); + + public DefaultIntentSupport( + Messaging messaging, + IntentResolver intentResolver, + long messageExchangeTimeout, + long appLaunchTimeout) { + this.messaging = messaging; + this.intentResolver = intentResolver; + this.messageExchangeTimeout = messageExchangeTimeout; + this.appLaunchTimeout = appLaunchTimeout; + } + + @Override + public CompletionStage findIntent(String intent, Context context, String resultType) { + FindIntentRequest request = new FindIntentRequest(); + request.setType(FindIntentRequestType.FIND_INTENT_REQUEST); + request.setMeta(messaging.createMeta()); + + FindIntentRequestPayload payload = new FindIntentRequestPayload(); + payload.setIntent(intent); + if (context != null) { + payload.setContext(context); + } + if (resultType != null) { + payload.setResultType(resultType); + } + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "findIntentResponse", messageExchangeTimeout) + .thenApply(response -> { + FindIntentResponse typedResponse = messaging.getConverter() + .convertValue(response, FindIntentResponse.class); + + if (typedResponse.getPayload() == null || + typedResponse.getPayload().getAppIntent() == null) { + throw new RuntimeException(ResolveError.NoAppsFound.toString()); + } + + // Schema types now use fdc3-standard types directly + AppIntent appIntent = typedResponse.getPayload().getAppIntent(); + if (appIntent.getApps() == null || appIntent.getApps().length == 0) { + throw new RuntimeException(ResolveError.NoAppsFound.toString()); + } + + return appIntent; + }); + } + + @Override + public CompletionStage> findIntentsByContext(Context context, String resultType) { + FindIntentsByContextRequest request = new FindIntentsByContextRequest(); + request.setType(FindIntentsByContextRequestType.FIND_INTENTS_BY_CONTEXT_REQUEST); + request.setMeta(messaging.createMeta()); + + FindIntentsByContextRequestPayload payload = new FindIntentsByContextRequestPayload(); + payload.setContext(context); + payload.setResultType(resultType); + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + + return messaging.>exchange(requestMap, "findIntentsByContextResponse", messageExchangeTimeout) + .thenApply(response -> { + FindIntentsByContextResponse typedResponse = messaging.getConverter() + .convertValue(response, FindIntentsByContextResponse.class); + + if (typedResponse.getPayload() == null || + typedResponse.getPayload().getAppIntents() == null || + typedResponse.getPayload().getAppIntents().isEmpty()) { + throw new RuntimeException(ResolveError.NoAppsFound.toString()); + } + + return typedResponse.getPayload().getAppIntents(); + }); + } + + @Override + public CompletionStage raiseIntent( + String intent, + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + // When no context is provided, substitute fdc3.nothing so the wire message remains valid. + Context resolvedContext = context != null ? context : new Context("fdc3.nothing"); + AddContextListenerRequestMeta meta = messaging.createMeta(); + + RaiseIntentRequest request = new RaiseIntentRequest(); + request.setType(RaiseIntentRequestType.RAISE_INTENT_REQUEST); + request.setMeta(meta); + + RaiseIntentRequestPayload payload = new RaiseIntentRequestPayload(); + payload.setIntent(intent); + payload.setContext(resolvedContext); + if (app != null) { + payload.setApp(app); + } + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + @SuppressWarnings("unchecked") + Map payloadMap = (Map) requestMap.get("payload"); + if (payloadMap != null) { + if (newInstance != null) { + payloadMap.put("newInstance", newInstance); + } else { + payloadMap.remove("newInstance"); + } + if (metadata != null) { + payloadMap.put("metadata", ContextMetadataMapper.toWire(metadata)); + } else { + payloadMap.remove("metadata"); + } + } + + return messaging.>exchange(requestMap, "raiseIntentResponse", appLaunchTimeout) + .thenCompose(response -> { + RaiseIntentResponse typedResponse = messaging.getConverter() + .convertValue(response, RaiseIntentResponse.class); + + AppIntent schemaAppIntent = typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getAppIntent(); + org.finos.fdc3.schema.IntentResolution schemaIntentResolution = + typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getIntentResolution(); + + ThrowIfUndefined.throwIfUndefined( + schemaAppIntent != null ? schemaAppIntent : schemaIntentResolution, + "Invalid response from Desktop Agent to raiseIntent, either " + + "payload.appIntent or payload.intentResolution must be set!", + response, + ResolveError.NoAppsFound.toString()); + + if (schemaAppIntent != null) { + return intentResolver.chooseIntent(List.of(schemaAppIntent), resolvedContext) + .thenCompose(choice -> { + if (choice == null) { + throw new RuntimeException(ResolveError.UserCancelled.toString()); + } + Boolean chosenNewInstance = choice.getAppId().getInstanceId() != null + ? null + : newInstance; + return raiseIntent( + intent, resolvedContext, choice.getAppId(), chosenNewInstance, metadata); + }); + } + + AppIdentifier source = schemaIntentResolution.getSource(); + String resolvedIntent = schemaIntentResolution.getIntent(); + ResultPromises promises = createResultPromises(meta.getRequestUUID(), source); + return CompletableFuture.completedFuture(new DefaultIntentResolution( + messaging, + messageExchangeTimeout, + promises.result, + promises.resultMetadata, + source, + resolvedIntent)); + }); + } + + @Override + public CompletionStage raiseIntentForContext( + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + AddContextListenerRequestMeta meta = messaging.createMeta(); + + RaiseIntentForContextRequest request = new RaiseIntentForContextRequest(); + request.setType(RaiseIntentForContextRequestType.RAISE_INTENT_FOR_CONTEXT_REQUEST); + request.setMeta(meta); + + RaiseIntentForContextRequestPayload payload = new RaiseIntentForContextRequestPayload(); + payload.setContext(context); + if (app != null) { + payload.setApp(app); + } + request.setPayload(payload); + + Map requestMap = messaging.getConverter().toMap(request); + @SuppressWarnings("unchecked") + Map raiseForContextPayload = (Map) requestMap.get("payload"); + if (raiseForContextPayload != null) { + if (newInstance != null) { + raiseForContextPayload.put("newInstance", newInstance); + } else { + raiseForContextPayload.remove("newInstance"); + } + if (metadata != null) { + raiseForContextPayload.put("metadata", ContextMetadataMapper.toWire(metadata)); + } else { + raiseForContextPayload.remove("metadata"); + } + } + + return messaging.>exchange(requestMap, "raiseIntentForContextResponse", appLaunchTimeout) + .thenCompose(response -> { + RaiseIntentForContextResponse typedResponse = messaging.getConverter() + .convertValue(response, RaiseIntentForContextResponse.class); + + List schemaAppIntents = typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getAppIntents(); + org.finos.fdc3.schema.IntentResolution schemaIntentResolution = + typedResponse.getPayload() == null + ? null + : typedResponse.getPayload().getIntentResolution(); + + ThrowIfUndefined.throwIfUndefined( + schemaAppIntents != null && !schemaAppIntents.isEmpty() + ? schemaAppIntents + : schemaIntentResolution, + "Invalid response from Desktop Agent to raiseIntentForContext, either " + + "payload.appIntents or payload.intentResolution must be set!", + response, + ResolveError.NoAppsFound.toString()); + + if (schemaAppIntents != null && !schemaAppIntents.isEmpty()) { + return intentResolver.chooseIntent(schemaAppIntents, context) + .thenCompose(choice -> { + if (choice == null) { + throw new RuntimeException(ResolveError.UserCancelled.toString()); + } + Boolean chosenNewInstance = choice.getAppId().getInstanceId() != null + ? null + : newInstance; + return raiseIntent( + choice.getIntent(), context, choice.getAppId(), chosenNewInstance, metadata); + }); + } + + AppIdentifier source = schemaIntentResolution.getSource(); + String resolvedIntent = schemaIntentResolution.getIntent(); + ResultPromises promises = createResultPromises(meta.getRequestUUID(), source); + return CompletableFuture.completedFuture(new DefaultIntentResolution( + messaging, + messageExchangeTimeout, + promises.result, + promises.resultMetadata, + source, + resolvedIntent)); + }); + } + + @Override + public CompletionStage addIntentListener(String intent, IntentHandler handler) { + return registerIntentListener(intent, null, handler); + } + + @Override + public CompletionStage addIntentListenerWithContext( + String intent, List contextTypes, IntentHandler handler) { + return registerIntentListener(intent, contextTypes, handler); + } + + private CompletionStage registerIntentListener( + String intent, List contextTypes, IntentHandler handler) { + DefaultIntentListener[] holder = new DefaultIntentListener[1]; + + // The conflict check and the insertion have to be one atomic step, otherwise two threads + // registering the same intent can both see no conflict and both register. + synchronized (intentListenerLock) { + if (hasConflictingListener(intent, contextTypes)) { + return CompletableFuture.failedFuture( + new RuntimeException(ResolveError.IntentListenerConflict.toString())); + } + + holder[0] = new DefaultIntentListener( + messaging, + intent, + contextTypes, + handler, + messageExchangeTimeout, + () -> intentListeners.remove(holder[0])); + intentListeners.add(holder[0]); + } + + // If the Desktop Agent rejects the registration, undo the reservation made above. + return holder[0].register() + .handle((ignored, error) -> { + if (error != null) { + intentListeners.remove(holder[0]); + throw error instanceof RuntimeException + ? (RuntimeException) error + : new RuntimeException(error); + } + return (Listener) holder[0]; + }); + } + + private boolean hasConflictingListener(String intent, List contextTypes) { + return intentListeners.stream().anyMatch(existing -> { + if (!existing.getIntent().equals(intent)) { + return false; + } + List existingTypes = existing.getContextTypes(); + if (existingTypes == null || contextTypes == null) { + return true; + } + return existingTypes.stream().anyMatch(contextTypes::contains); + }); + } + + private static final class ResultPromises { + final CompletionStage result; + final CompletionStage resultMetadata; + + ResultPromises(CompletionStage result, CompletionStage resultMetadata) { + this.result = result; + this.resultMetadata = resultMetadata; + } + } + + @SuppressWarnings("unchecked") + private ResultPromises createResultPromises(String requestUuid, AppIdentifier source) { + CompletableFuture metadataFuture = new CompletableFuture<>(); + CompletionStage result = messaging.>waitFor( + m -> { + String type = (String) m.get("type"); + Map meta = (Map) m.get("meta"); + String respRequestUuid = meta != null ? (String) meta.get("requestUuid") : null; + return "raiseIntentResultResponse".equals(type) && requestUuid.equals(respRequestUuid); + }, + // Bounded deliberately. waitFor only schedules a timeout when this is positive, + // so passing 0 left the listener registered forever whenever the resolving app + // never sent a result. + appLaunchTimeout, + ResultError.ApiTimeout.toString() + ).thenApply(response -> { + metadataFuture.complete(extractResultMetadata(response, source)); + Map payload = (Map) response.get("payload"); + return convertIntentResult(payload.get("intentResult")); + }); + + // Without this the metadata stage stays pending forever when the result times out. + result.whenComplete((ignored, error) -> { + if (error != null) { + metadataFuture.completeExceptionally(error); + } + }); + + return new ResultPromises(result, metadataFuture); + } + + @SuppressWarnings("unchecked") + private static ContextMetadata extractResultMetadata(Map response, AppIdentifier source) { + Map payload = (Map) response.get("payload"); + Map resultMetadata = payload != null + ? (Map) payload.get("resultMetadata") + : null; + ContextMetadata metadata = ContextMetadataMapper.fromWire( + resultMetadata, null, ContextMetadataMapper.MissingTraceId.EMPTY); + metadata.setSource(source); + return metadata; + } + + @SuppressWarnings("unchecked") + private IntentResult convertIntentResult(Object intentResultObj) { + if (intentResultObj == null) { + return null; + } + if (!(intentResultObj instanceof Map)) { + return null; + } + Map intentResult = (Map) intentResultObj; + if (intentResult.isEmpty()) { + return null; + } + Object contextObj = intentResult.get("context"); + if (contextObj != null) { + if (contextObj instanceof Context) { + return (Context) contextObj; + } + return Context.fromMap((Map) contextObj); + } + Object channelObj = intentResult.get("channel"); + if (channelObj instanceof Map) { + return createChannel((Map) channelObj); + } + return null; + } + + @SuppressWarnings("unchecked") + private Channel createChannel(Map channelMap) { + String id = (String) channelMap.get("id"); + Object typeObj = channelMap.get("type"); + Channel.Type type = Channel.Type.App; + if (typeObj != null) { + String typeStr = typeObj.toString(); + if ("user".equals(typeStr)) { + type = Channel.Type.User; + } else if ("private".equals(typeStr)) { + type = Channel.Type.Private; + } + } + Map displayMetadataMap = (Map) channelMap.get("displayMetadata"); + org.finos.fdc3.api.metadata.DisplayMetadata displayMetadata = null; + if (displayMetadataMap != null) { + displayMetadata = org.finos.fdc3.api.metadata.DisplayMetadata.fromMap(displayMetadataMap); + } + if (type == Channel.Type.Private) { + return new DefaultPrivateChannel(messaging, messageExchangeTimeout, id); + } + return new DefaultChannel(messaging, messageExchangeTimeout, id, type, displayMetadata); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/IntentSupport.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/IntentSupport.java new file mode 100644 index 00000000..3a869f1c --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/intents/IntentSupport.java @@ -0,0 +1,105 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.intents; + +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.Listener; + +/** + * Interface for intent-related operations. + */ +public interface IntentSupport { + + /** + * Find applications that can handle a specific intent. + * + * @param intent the intent name + * @param context optional context to filter by + * @param resultType optional result type to filter by + * @return a CompletionStage containing the app intent information + */ + CompletionStage findIntent(String intent, Context context, String resultType); + + /** + * Find intents that can handle a specific context. + * + * @param context the context to find intents for + * @param resultType the required result type, or null for any + * @return a CompletionStage containing the list of app intents + */ + CompletionStage> findIntentsByContext(Context context, String resultType); + + /** + * Raise an intent. + * + * @param intent the intent name + * @param context the context to pass + * @param app optional target application + * @param newInstance optional instance selection preference + * @param metadata optional app-provided metadata + * @return a CompletionStage containing the intent resolution + */ + CompletionStage raiseIntent( + String intent, + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata); + + /** + * Raise an intent for a context. + * + * @param context the context + * @param app optional target application + * @param newInstance optional instance selection preference + * @param metadata optional app-provided metadata + * @return a CompletionStage containing the intent resolution + */ + CompletionStage raiseIntentForContext( + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata); + + /** + * Add an intent listener. + * + * @param intent the intent to listen for + * @param handler the intent handler + * @return a CompletionStage containing the listener + */ + CompletionStage addIntentListener(String intent, IntentHandler handler); + + /** + * Add an intent listener filtered by context type(s). + * + * @param intent the intent to listen for + * @param contextTypes one or more context types to filter by + * @param handler the intent handler + * @return a CompletionStage containing the listener + */ + CompletionStage addIntentListenerWithContext( + String intent, List contextTypes, IntentHandler handler); +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractListener.java new file mode 100644 index 00000000..607d978c --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractListener.java @@ -0,0 +1,164 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.errors.ChannelError; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.ThrowIfUndefined; + +/** + * Common base for all listeners - handles registration and unregistration with messaging + * and sends notification messages when connected and disconnected. + * + * This mirrors the TypeScript AbstractListener pattern. + * + * @param The handler type (e.g., ContextHandler, IntentHandler, EventHandler) + */ +public abstract class AbstractListener implements RegisterableListener, Listener { + + protected final Messaging messaging; + protected final long messageExchangeTimeout; + protected final H handler; + + private final String subscribeRequestType; + private final String subscribeResponseType; + private final String unsubscribeRequestType; + private final String unsubscribeResponseType; + + // The listener ID assigned by the server + protected String id = null; + + /** + * Construct an AbstractListener. + * + * @param messaging the messaging system + * @param messageExchangeTimeout timeout for message exchanges + * @param handler the handler callback + * @param subscribeRequestType the type string for subscribe requests (e.g., "addContextListenerRequest") + * @param subscribeResponseType the type string for subscribe responses (e.g., "addContextListenerResponse") + * @param unsubscribeRequestType the type string for unsubscribe requests (e.g., "contextListenerUnsubscribeRequest") + * @param unsubscribeResponseType the type string for unsubscribe responses (e.g., "contextListenerUnsubscribeResponse") + */ + protected AbstractListener( + Messaging messaging, + long messageExchangeTimeout, + H handler, + String subscribeRequestType, + String subscribeResponseType, + String unsubscribeRequestType, + String unsubscribeResponseType) { + this.messaging = messaging; + this.messageExchangeTimeout = messageExchangeTimeout; + this.handler = handler; + this.subscribeRequestType = subscribeRequestType; + this.subscribeResponseType = subscribeResponseType; + this.unsubscribeRequestType = unsubscribeRequestType; + this.unsubscribeResponseType = unsubscribeResponseType; + } + + @Override + public String getId() { + return id; + } + + /** + * Filter function to determine if a message should be processed. + * Subclasses implement this to define their filtering logic. + * + * @param message the incoming message + * @return true if the message should be processed + */ + @Override + public abstract boolean filter(Map message); + + /** + * Action to perform when a matching message is received. + * Subclasses implement this to define their handling logic. + * + * @param message the matched message + */ + @Override + public abstract void action(Map message); + + /** + * Build the subscription request payload. + * Subclasses implement this to provide their specific payload. + * + * @return the subscription request as a Map + */ + protected abstract Map buildSubscribeRequest(); + + @Override + @SuppressWarnings("unchecked") + public CompletionStage register() { + Map request; + try { + request = buildSubscribeRequest(); + } catch (RuntimeException e) { + // Subclasses validate their event type while building the payload. Report that as a + // rejected stage rather than throwing out of an async method. + return CompletableFuture.failedFuture(e); + } + request.put("type", subscribeRequestType); + request.put("meta", messaging.getConverter().toMap(messaging.createMeta())); + + return messaging.>exchange(request, subscribeResponseType, messageExchangeTimeout) + .thenAccept(response -> { + // Extract listenerUUID from the response + Map payload = (Map) response.get("payload"); + if (payload != null) { + this.id = (String) payload.get("listenerUUID"); + } + + ThrowIfUndefined.throwIfUndefined( + this.id, + "The Desktop Agent's response did not include a listenerUUID, " + + "which will mean this listener can't be removed!", + response, + ChannelError.CreationFailed.toString()); + + messaging.register(this); + }); + } + + @Override + public CompletionStage unsubscribe() { + if (this.id != null) { + messaging.unregister(this.id); + + Map request = new java.util.HashMap<>(); + request.put("type", unsubscribeRequestType); + request.put("meta", messaging.getConverter().toMap(messaging.createMeta())); + + Map payload = new java.util.HashMap<>(); + payload.put("listenerUUID", this.id); + request.put("payload", payload); + + return messaging.>exchange(request, unsubscribeResponseType, messageExchangeTimeout) + .thenAccept(response -> { /* completed */ }); + } else { + return CompletableFuture.failedFuture(new RuntimeException( + "This listener doesn't have an id and hence can't be removed!")); + } + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractPrivateChannelEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractPrivateChannelEventListener.java new file mode 100644 index 00000000..cd56cffd --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/AbstractPrivateChannelEventListener.java @@ -0,0 +1,106 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.schema.PrivateChannelEventType; + +/** + * Abstract base class for private channel event listeners. + * Extends AbstractListener to handle registration/unregistration. + */ +public abstract class AbstractPrivateChannelEventListener extends AbstractListener { + + protected final String privateChannelId; + protected final List eventMessageTypes; + protected final String eventType; + + protected AbstractPrivateChannelEventListener( + Messaging messaging, + long messageExchangeTimeout, + String privateChannelId, + List eventMessageTypes, + String eventType, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + handler, + "privateChannelAddEventListenerRequest", + "privateChannelAddEventListenerResponse", + "privateChannelUnsubscribeEventListenerRequest", + "privateChannelUnsubscribeEventListenerResponse" + ); + this.privateChannelId = privateChannelId; + this.eventMessageTypes = eventMessageTypes; + this.eventType = eventType; + } + + @Override + protected Map buildSubscribeRequest() { + Map request = new HashMap<>(); + Map payload = new HashMap<>(); + payload.put("privateChannelId", privateChannelId); + PrivateChannelEventType pcEventType = toPrivateChannelEventType(eventType); + // Explicitly set listenerType to null if eventType is null, otherwise use the enum value + payload.put("listenerType", pcEventType != null ? pcEventType.toValue() : null); + request.put("payload", payload); + return request; + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + String type = (String) message.get("type"); + if (!eventMessageTypes.contains(type)) { + return false; + } + + Map payload = (Map) message.get("payload"); + if (payload == null) { + return false; + } + + String msgChannelId = (String) payload.get("privateChannelId"); + return privateChannelId.equals(msgChannelId); + } + + @Override + public abstract void action(Map message); + + private PrivateChannelEventType toPrivateChannelEventType(String eventType) { + if (eventType == null) { + return null; + } + switch (eventType) { + case "addContextListener": + return PrivateChannelEventType.ADD_CONTEXT_LISTENER; + case "unsubscribe": + return PrivateChannelEventType.UNSUBSCRIBE; + case "disconnect": + return PrivateChannelEventType.DISCONNECT; + default: + throw new RuntimeException("Unsupported event type: " + eventType); + } + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/ChannelEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/ChannelEventListener.java new file mode 100644 index 00000000..0abdc4e5 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/ChannelEventListener.java @@ -0,0 +1,100 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; + +/** + * Listens to Channel-scoped events (currently {@code contextCleared}) for a specific Channel. + * Registration is sent to the Desktop Agent over DACP with the Channel's id so the Desktop + * Agent can route events to this app, and inbound events are additionally filtered locally by + * {@code channelId} so that only events for this Channel are delivered to the handler. + */ +public class ChannelEventListener extends AbstractListener { + + private final FDC3Event.Type type; + private final String channelId; + + public ChannelEventListener( + Messaging messaging, + long messageExchangeTimeout, + String type, + String channelId, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + handler, + "addEventListenerRequest", + "addEventListenerResponse", + "eventListenerUnsubscribeRequest", + "eventListenerUnsubscribeResponse" + ); + this.type = parseChannelEventType(type); + this.channelId = channelId; + } + + private static FDC3Event.Type parseChannelEventType(String type) { + if (type == null) { + return null; + } + try { + FDC3Event.Type parsed = FDC3Event.Type.fromValue(type); + if (parsed == FDC3Event.Type.CONTEXT_CLEARED) { + return parsed; + } + } catch (IllegalArgumentException e) { + // fall through + } + throw new RuntimeException("UnknownEventType"); + } + + @Override + protected Map buildSubscribeRequest() { + Map request = new HashMap<>(); + Map payload = new HashMap<>(); + payload.put("type", type != null ? type.toWireValue() : null); + payload.put("channelId", channelId); + request.put("payload", payload); + return request; + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + if (!FDC3Event.Type.CONTEXT_CLEARED.toMessageType().equals(message.get("type"))) { + return false; + } + Map payload = (Map) message.get("payload"); + return payload != null && channelId.equals(payload.get("channelId")); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + Map payload = (Map) message.get("payload"); + Map details = new HashMap<>(); + details.put("channelId", payload.get("channelId")); + details.put("contextType", payload.get("contextType")); + handler.handleEvent(new FDC3Event(FDC3Event.Type.CONTEXT_CLEARED, details)); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultContextListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultContextListener.java new file mode 100644 index 00000000..8d38f973 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultContextListener.java @@ -0,0 +1,182 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Default implementation of a context listener. + * Extends AbstractListener to handle registration/unregistration. + *

+ * Context types are always held as a {@link List}{@code String}, or {@code null} for all types. + * On the wire, a single type (or all-types) uses {@code contextType}; multiple types use + * {@code contextTypes}. + */ +public class DefaultContextListener extends AbstractListener { + + protected String channelId; + /** + * Types to match, or {@code null} for all types. + */ + protected final List contextTypes; + protected final String messageType; + + public DefaultContextListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + List contextTypes, + ContextHandler handler) { + this(messaging, messageExchangeTimeout, channelId, contextTypes, handler, "broadcastEvent"); + } + + public DefaultContextListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + List contextTypes, + ContextHandler handler, + String messageType) { + super( + messaging, + messageExchangeTimeout, + handler, + "addContextListenerRequest", + "addContextListenerResponse", + "contextListenerUnsubscribeRequest", + "contextListenerUnsubscribeResponse" + ); + this.channelId = channelId; + this.contextTypes = contextTypes; + this.messageType = messageType; + } + + /** + * Update the channel this listener is listening to. This is used for non-user + * channel listeners (e.g., app channels, private channels). + * + * @param channel the new channel to listen to + */ + public void changeChannel(Channel channel) { + if (channel == null) { + this.channelId = null; + } else { + this.channelId = channel.getId(); + replayCurrentContext(channel) + .exceptionally(error -> { + Logger.error("Failed to replay current context of type {} from channel {}", + contextTypes, this.channelId, error); + return null; + }); + } + } + + /** + * Replays matching current context from the given channel into the handler. + */ + protected CompletionStage replayCurrentContext(Channel channel) { + if (contextTypes != null) { + CompletionStage chain = CompletableFuture.completedFuture(null); + for (String ct : contextTypes) { + chain = chain.thenCompose(ignored -> + channel.getCurrentContextWithMetadata(ct).thenAccept(result -> { + result.ifPresent(cwm -> handler.handleContext(cwm.getContext(), cwm.getMetadata())); + })); + } + return chain; + } + return channel.getCurrentContextWithMetadata(null) + .thenAccept(result -> { + result.ifPresent(cwm -> handler.handleContext(cwm.getContext(), cwm.getMetadata())); + }); + } + + protected boolean matchesContextType(String msgContextType) { + if (contextTypes == null) { + return true; + } + return contextTypes.contains(msgContextType); + } + + @Override + protected Map buildSubscribeRequest() { + Map request = new HashMap<>(); + Map payload = new HashMap<>(); + payload.put("channelId", channelId); + if (contextTypes != null && contextTypes.size() > 1) { + payload.put("contextTypes", contextTypes); + } else { + payload.put("contextType", contextTypes == null ? null : contextTypes.get(0)); + } + request.put("payload", payload); + return request; + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + String type = (String) message.get("type"); + if (!messageType.equals(type)) { + return false; + } + + Map payload = (Map) message.get("payload"); + if (payload == null) { + return false; + } + + String msgChannelId = (String) payload.get("channelId"); + if (channelId != null && !channelId.equals(msgChannelId)) { + return false; + } + + Map context = (Map) payload.get("context"); + if (context == null) { + return false; + } + + String msgContextType = (String) context.get("type"); + return matchesContextType(msgContextType); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + Map payload = (Map) message.get("payload"); + Map contextMap = (Map) payload.get("context"); + Context context = Context.fromMap(contextMap); + Map messageMeta = (Map) message.get("meta"); + Map payloadMetadata = (Map) payload.get("metadata"); + Object messageTimestamp = messageMeta != null ? messageMeta.get("timestamp") : null; + ContextMetadata metadata = ContextMetadataMapper.fromWire( + payloadMetadata, messageTimestamp, messageMeta, + ContextMetadataMapper.MissingTraceId.LEAVE_ABSENT); + handler.handleContext(context, metadata); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultIntentListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultIntentListener.java new file mode 100644 index 00000000..d017c6bf --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DefaultIntentListener.java @@ -0,0 +1,273 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.types.ContextWithMetadata; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.schema.IntentEvent; +import org.finos.fdc3.schema.IntentResultRequest; +import org.finos.fdc3.schema.IntentResultRequestPayload; +import org.finos.fdc3.schema.IntentResultRequestType; + +/** + * Default implementation of an intent listener. + * Extends AbstractListener to handle registration/unregistration. + */ +public class DefaultIntentListener extends AbstractListener { + + private final String intent; + private final List contextTypes; + private final Runnable onUnsubscribe; + + public DefaultIntentListener( + Messaging messaging, + String intent, + IntentHandler handler, + long messageExchangeTimeout) { + this(messaging, intent, null, handler, messageExchangeTimeout, null); + } + + public DefaultIntentListener( + Messaging messaging, + String intent, + List contextTypes, + IntentHandler handler, + long messageExchangeTimeout, + Runnable onUnsubscribe) { + super( + messaging, + messageExchangeTimeout, + handler, + "addIntentListenerRequest", + "addIntentListenerResponse", + "intentListenerUnsubscribeRequest", + "intentListenerUnsubscribeResponse" + ); + this.intent = intent; + this.contextTypes = contextTypes; + this.onUnsubscribe = onUnsubscribe; + } + + @Override + protected Map buildSubscribeRequest() { + Map request = new HashMap<>(); + Map payload = new HashMap<>(); + payload.put("intent", intent); + if (contextTypes != null) { + payload.put("contextTypes", contextTypes); + } + request.put("payload", payload); + return request; + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + String type = (String) message.get("type"); + if (!"intentEvent".equals(type)) { + return false; + } + + Map payload = (Map) message.get("payload"); + if (payload == null) { + return false; + } + + String msgIntent = (String) payload.get("intent"); + if (!intent.equals(msgIntent)) { + return false; + } + + if (contextTypes == null) { + return true; + } + + Object contextObj = payload.get("context"); + if (!(contextObj instanceof Map)) { + return false; + } + String contextType = (String) ((Map) contextObj).get("type"); + return contextTypes.contains(contextType); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + IntentEvent intentEvent = messaging.getConverter().convertValue(message, IntentEvent.class); + + Context context = intentEvent.getPayload().getContext(); + Map messageMap = message; + Map payloadMap = (Map) messageMap.get("payload"); + Map payloadMetadata = payloadMap != null + ? (Map) payloadMap.get("metadata") + : null; + Object messageTimestamp = messageMap.get("meta") != null + ? ((Map) messageMap.get("meta")).get("timestamp") + : null; + ContextMetadata contextMetadata = ContextMetadataMapper.fromWire( + payloadMetadata, messageTimestamp, ContextMetadataMapper.MissingTraceId.GENERATE); + + CompletionStage> resultFuture = handler.handleIntent(context, contextMetadata); + handleIntentResult(resultFuture, intentEvent); + } + + @Override + public CompletionStage unsubscribe() { + return super.unsubscribe().thenRun(() -> { + if (onUnsubscribe != null) { + onUnsubscribe.run(); + } + }); + } + + public String getIntent() { + return intent; + } + + public List getContextTypes() { + return contextTypes; + } + + private void handleIntentResult( + CompletionStage> resultFuture, + IntentEvent intentEvent) { + + resultFuture.thenAccept(optionalResult -> { + UnwrappedIntentResult unwrapped = unwrapIntentResult(optionalResult.orElse(null)); + IntentResultRequest request = createIntentResultRequest( + unwrapped.result, unwrapped.appMetadata, intentEvent); + + Map requestMap = messaging.getConverter().toMap(request); + if (unwrapped.appMetadata != null) { + @SuppressWarnings("unchecked") + Map payload = (Map) requestMap.get("payload"); + if (payload != null) { + payload.put("metadata", ContextMetadataMapper.toWire(unwrapped.appMetadata)); + } + } + + messaging.>exchange( + requestMap, + "intentResultResponse", + messageExchangeTimeout + ).exceptionally(ex -> { + Logger.error("Failed to send the result of intent {}", intent, ex); + return null; + }); + }).exceptionally(ex -> { + // Do not send a void intentResultRequest on reject — that looks like success to the DA. + Logger.error("Handler for intent {} rejected; no intent result will be sent", intent, ex); + return null; + }); + } + + private static final class UnwrappedIntentResult { + final IntentResult result; + final AppProvidableContextMetadata appMetadata; + + UnwrappedIntentResult(IntentResult result, AppProvidableContextMetadata appMetadata) { + this.result = result; + this.appMetadata = appMetadata; + } + } + + private static UnwrappedIntentResult unwrapIntentResult(Object raw) { + if (raw instanceof ContextWithMetadata) { + ContextWithMetadata cwm = (ContextWithMetadata) raw; + return new UnwrappedIntentResult(cwm.getContext(), cwm.getMetadata()); + } + if (raw instanceof IntentResult) { + return new UnwrappedIntentResult((IntentResult) raw, null); + } + return new UnwrappedIntentResult(null, null); + } + + private IntentResultRequest createIntentResultRequest( + IntentResult apiResult, + AppProvidableContextMetadata appMetadata, + IntentEvent intentEvent) { + + IntentResultRequest request = new IntentResultRequest(); + request.setType(IntentResultRequestType.INTENT_RESULT_REQUEST); + + org.finos.fdc3.schema.AddContextListenerRequestMeta meta = + new org.finos.fdc3.schema.AddContextListenerRequestMeta(); + meta.setRequestUUID(intentEvent.getMeta().getEventUUID()); + meta.setTimestamp(OffsetDateTime.now()); + request.setMeta(meta); + + IntentResultRequestPayload payload = new IntentResultRequestPayload(); + payload.setIntentEventUUID(intentEvent.getMeta().getEventUUID()); + payload.setRaiseIntentRequestUUID(intentEvent.getPayload().getRaiseIntentRequestUUID()); + payload.setIntentResult(convertIntentResult(apiResult)); + request.setPayload(payload); + + return request; + } + + private org.finos.fdc3.schema.IntentResult convertIntentResult(IntentResult apiResult) { + org.finos.fdc3.schema.IntentResult schemaResult = new org.finos.fdc3.schema.IntentResult(); + + if (apiResult == null) { + return schemaResult; + } + + if (apiResult instanceof Context) { + schemaResult.setContext((Context) apiResult); + } else if (apiResult instanceof Channel) { + Channel channel = (Channel) apiResult; + org.finos.fdc3.schema.Channel schemaChannel = new org.finos.fdc3.schema.Channel(); + schemaChannel.setID(channel.getId()); + schemaChannel.setType(convertChannelType(channel.getType())); + schemaChannel.setDisplayMetadata(null); + schemaResult.setChannel(schemaChannel); + } + + return schemaResult; + } + + private org.finos.fdc3.schema.Type convertChannelType(Channel.Type type) { + if (type == null) { + return null; + } + switch (type) { + case User: + return org.finos.fdc3.schema.Type.USER; + case App: + return org.finos.fdc3.schema.Type.APP; + case Private: + return org.finos.fdc3.schema.Type.PRIVATE; + default: + return null; + } + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DesktopAgentEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DesktopAgentEventListener.java new file mode 100644 index 00000000..4d4482c6 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/DesktopAgentEventListener.java @@ -0,0 +1,129 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; + +/** + * Listener for Desktop Agent events. + * Extends AbstractListener to handle registration/unregistration. + */ +public class DesktopAgentEventListener extends AbstractListener { + + private final FDC3Event.Type eventType; + + public DesktopAgentEventListener( + Messaging messaging, + long messageExchangeTimeout, + String eventType, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + handler, + "addEventListenerRequest", + "addEventListenerResponse", + "eventListenerUnsubscribeRequest", + "eventListenerUnsubscribeResponse" + ); + this.eventType = parseDesktopAgentEventType(eventType); + } + + /** + * Parses and validates a Desktop Agent event type string. + * {@code null} means listen to all events. Throws {@code RuntimeException} + * with message {@code UnknownEventType} if not a Desktop Agent event type. + */ + private static FDC3Event.Type parseDesktopAgentEventType(String eventType) { + if (eventType == null) { + return null; + } + final FDC3Event.Type type; + try { + type = FDC3Event.Type.fromValue(eventType); + } catch (IllegalArgumentException e) { + throw new RuntimeException("UnknownEventType"); + } + switch (type) { + case USER_CHANNEL_CHANGED: + case CONTEXT_CLEARED: + return type; + default: + throw new RuntimeException("UnknownEventType"); + } + } + + @Override + protected Map buildSubscribeRequest() { + Map request = new HashMap<>(); + Map payload = new HashMap<>(); + payload.put("type", eventType != null ? eventType.toWireValue() : null); + // Desktop Agent-level listeners are registered with a null channelId + payload.put("channelId", null); + request.put("payload", payload); + return request; + } + + @Override + public boolean filter(Map message) { + String messageType = (String) message.get("type"); + if (messageType == null) { + return false; + } + if (eventType == null) { + // Wildcard listeners receive agent events only, not request/response traffic. + return !messageType.endsWith("Response") && !messageType.endsWith("Request"); + } + return eventType.toMessageType().equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + String messageType = (String) message.get("type"); + Map payload = (Map) message.get("payload"); + + FDC3Event.Type resolvedType = FDC3Event.Type.fromMessageType(messageType); + Object details = buildEventDetails(resolvedType, payload); + handler.handleEvent(new FDC3Event(resolvedType, details)); + } + + private static Object buildEventDetails(FDC3Event.Type type, Map payload) { + if (type == FDC3Event.Type.USER_CHANNEL_CHANGED) { + Map details = new HashMap<>(); + Object currentChannelId = payload.get("currentChannelId"); + if (currentChannelId == null) { + currentChannelId = payload.get("newChannelId"); + } + details.put("currentChannelId", currentChannelId); + return details; + } + if (type == FDC3Event.Type.CONTEXT_CLEARED) { + Map details = new HashMap<>(); + details.put("channelId", payload.get("channelId")); + details.put("contextType", payload.get("contextType")); + return details; + } + return payload; + } + +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelAddContextEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelAddContextEventListener.java new file mode 100644 index 00000000..72fbd964 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelAddContextEventListener.java @@ -0,0 +1,66 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Listener for private channel addContextListener events. + */ +public class PrivateChannelAddContextEventListener extends AbstractPrivateChannelEventListener { + + public PrivateChannelAddContextEventListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + channelId, + Arrays.asList("privateChannelOnAddContextListenerEvent"), + "addContextListener", + handler + ); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + String type = (String) message.get("type"); + + if ("privateChannelOnAddContextListenerEvent".equals(type)) { + Map payload = (Map) message.get("payload"); + Map details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + details.put("contextType", payload.get("contextType")); + + FDC3Event event = new FDC3Event(FDC3Event.Type.ADD_CONTEXT_LISTENER, details); + handler.handleEvent(event); + } else { + Logger.error("PrivateChannelAddContextEventListener was called for a different message type: " + type); + } + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelDisconnectEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelDisconnectEventListener.java new file mode 100644 index 00000000..c7751e54 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelDisconnectEventListener.java @@ -0,0 +1,64 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Listener for private channel disconnect events. + */ +public class PrivateChannelDisconnectEventListener extends AbstractPrivateChannelEventListener { + + public PrivateChannelDisconnectEventListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + channelId, + Arrays.asList("privateChannelOnDisconnectEvent"), + "disconnect", + handler + ); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + String type = (String) message.get("type"); + + if ("privateChannelOnDisconnectEvent".equals(type)) { + Map payload = (Map) message.get("payload"); + Map details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + FDC3Event event = new FDC3Event(FDC3Event.Type.ON_DISCONNECT, details); + handler.handleEvent(event); + } else { + Logger.error("PrivateChannelDisconnectEventListener was called for a different message type: " + type); + } + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelNullEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelNullEventListener.java new file mode 100644 index 00000000..48a402eb --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelNullEventListener.java @@ -0,0 +1,88 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Listener for all private channel events (null event type). + */ +public class PrivateChannelNullEventListener extends AbstractPrivateChannelEventListener { + + public PrivateChannelNullEventListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + channelId, + Arrays.asList( + "privateChannelOnAddContextListenerEvent", + "privateChannelOnUnsubscribeEvent", + "privateChannelOnDisconnectEvent" + ), + null, // eventType is null for listening to all events + handler + ); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + String type = (String) message.get("type"); + Map payload = (Map) message.get("payload"); + + FDC3Event.Type eventType; + Map details; + + switch (type) { + case "privateChannelOnAddContextListenerEvent": + eventType = FDC3Event.Type.ADD_CONTEXT_LISTENER; + details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + details.put("contextType", payload.get("contextType")); + break; + case "privateChannelOnUnsubscribeEvent": + eventType = FDC3Event.Type.ON_UNSUBSCRIBE; + details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + details.put("contextType", payload.get("contextType")); + break; + case "privateChannelOnDisconnectEvent": + eventType = FDC3Event.Type.ON_DISCONNECT; + details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + break; + default: + Logger.error("PrivateChannelNullEventListener received unexpected message type: " + type); + return; + } + + FDC3Event event = new FDC3Event(eventType, details); + handler.handleEvent(event); + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelUnsubscribeEventListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelUnsubscribeEventListener.java new file mode 100644 index 00000000..46bfb70d --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/PrivateChannelUnsubscribeEventListener.java @@ -0,0 +1,66 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Listener for private channel unsubscribe events. + */ +public class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChannelEventListener { + + public PrivateChannelUnsubscribeEventListener( + Messaging messaging, + long messageExchangeTimeout, + String channelId, + EventHandler handler) { + super( + messaging, + messageExchangeTimeout, + channelId, + Arrays.asList("privateChannelOnUnsubscribeEvent"), + "unsubscribe", + handler + ); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + String type = (String) message.get("type"); + + if ("privateChannelOnUnsubscribeEvent".equals(type)) { + Map payload = (Map) message.get("payload"); + Map details = new HashMap<>(); + details.put("channelId", payload.get("privateChannelId")); + details.put("contextType", payload.get("contextType")); + + FDC3Event event = new FDC3Event(FDC3Event.Type.ON_UNSUBSCRIBE, details); + handler.handleEvent(event); + } else { + Logger.error("PrivateChannelUnsubscribeEventListener was called for a different message type: " + type); + } + } +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/RegisterableListener.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/RegisterableListener.java new file mode 100644 index 00000000..2c8f12a4 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/listeners/RegisterableListener.java @@ -0,0 +1,65 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.listeners; + +import java.util.Map; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.types.Listener; + +/** + * A listener that can be registered with the messaging system. + */ +public interface RegisterableListener extends Listener { + + /** + * Get the unique identifier for this listener. + * + * @return the listener ID + */ + String getId(); + + /** + * Filter function to determine if a message should be processed. + * + * @param message the incoming message + * @return true if the message should be processed + */ + boolean filter(Map message); + + /** + * Action to perform when a matching message is received. + * + * @param message the matched message + */ + void action(Map message); + + /** + * Register this listener with the messaging system. + * + * @return a CompletionStage that completes when registered + */ + CompletionStage register(); + + /** + * Unsubscribe this listener from the messaging system. + * + * @return a CompletionStage that completes when unsubscribed + */ + CompletionStage unsubscribe(); +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/messaging/AbstractMessaging.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/messaging/AbstractMessaging.java new file mode 100644 index 00000000..2df6dc37 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/messaging/AbstractMessaging.java @@ -0,0 +1,242 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.messaging; + +import java.time.OffsetDateTime; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; + +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.Messaging; +import org.finos.fdc3.proxy.listeners.RegisterableListener; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.util.MessageLogging; +import org.finos.fdc3.schema.AddContextListenerRequestMeta; +import org.finos.fdc3.schema.SchemaConverter; + +/** + * Abstract base class for messaging implementations. + */ +public abstract class AbstractMessaging implements Messaging { + + private static final String API_TIMEOUT = "ApiTimeout"; + + /** + * Schedules the timeouts for {@link #waitFor}. Per instance and daemon so that an + * application which returns from {@code main} without calling {@link #disconnect()} still + * exits, and so that {@link #shutdownScheduler()} cannot affect another connection. + */ + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r, "fdc3-messaging-timeouts"); + thread.setDaemon(true); + return thread; + }); + + private AppIdentifier appIdentifier; + private final SchemaConverter converter; + + protected AbstractMessaging(AppIdentifier appIdentifier) { + this.appIdentifier = appIdentifier; + this.converter = new SchemaConverter(); + } + + /** + * Stops the timeout scheduler. Subclasses must call this from {@link #disconnect()} so the + * thread does not outlive the connection. + */ + protected void shutdownScheduler() { + scheduler.shutdownNow(); + } + + /** + * Sets the identity for this messaging instance after validation. + * This is called after the handshake when the Desktop Agent provides + * the validated AppIdentifier. + * + * @param appIdentifier the validated app identifier + */ + public void setIdentifier(AppIdentifier appIdentifier) { + this.appIdentifier = appIdentifier; + } + + @Override + public abstract String createUUID(); + + @Override + public abstract CompletionStage post(Map message); + + @Override + public abstract void register(RegisterableListener listener); + + @Override + public abstract void unregister(String id); + + @Override + public AddContextListenerRequestMeta createMeta() { + AddContextListenerRequestMeta meta = new AddContextListenerRequestMeta(); + meta.setRequestUUID(createUUID()); + meta.setTimestamp(OffsetDateTime.now()); + + if (appIdentifier != null) { + // Copied rather than shared so that a later setIdentifier cannot alter the source of + // a message already in flight. The desktopAgent field is carried through as the + // Desktop Agent supplied it during the handshake; inventing a value here would have + // every message misreport which agent it came from. + meta.setSource(new AppIdentifier( + appIdentifier.getAppId(), + appIdentifier.getInstanceId(), + appIdentifier.getDesktopAgent())); + } + return meta; + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage waitFor(Predicate filter, long timeoutMs, String timeoutErrorMessage) { + String id = createUUID(); + CompletableFuture future = new CompletableFuture<>(); + + final ScheduledFuture[] timeoutFuture = new ScheduledFuture[1]; + + RegisterableListener listener = new RegisterableListener() { + @Override + public String getId() { + return id; + } + + @Override + public boolean filter(Map message) { + try { + return filter.test((X) message); + } catch (ClassCastException e) { + return false; + } + } + + @Override + public void action(Map message) { + Logger.debug("Received from DesktopAgent: {}", MessageLogging.summarise(message)); + if (Logger.isPayloadEnabled()) { + Logger.payload("Received from DesktopAgent: {}", MessageLogging.redact(message)); + } + unregister(id); + if (timeoutFuture[0] != null) { + timeoutFuture[0].cancel(false); + } + future.complete((X) message); + } + + @Override + public CompletionStage register() { + AbstractMessaging.this.register(this); + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage unsubscribe() { + AbstractMessaging.this.unregister(id); + return CompletableFuture.completedFuture(null); + } + }; + + register(listener); + + if (timeoutMs > 0) { + timeoutFuture[0] = scheduler.schedule(() -> { + unregister(id); + if (!future.isDone()) { + Logger.error("waitFor rejecting after {}ms with {}", timeoutMs, timeoutErrorMessage); + future.completeExceptionally(new RuntimeException(timeoutErrorMessage)); + } + }, timeoutMs, TimeUnit.MILLISECONDS); + } + + return future; + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage exchange(Map message, String expectedTypeName, long timeoutMs) { + Map meta = (Map) message.get("meta"); + String requestUuid = (String) meta.get("requestUuid"); + + CompletionStage promise = waitFor( + m -> { + Map msg = (Map) m; + String type = (String) msg.get("type"); + Map msgMeta = (Map) msg.get("meta"); + String respRequestUuid = msgMeta != null ? (String) msgMeta.get("requestUuid") : null; + return expectedTypeName.equals(type) && requestUuid.equals(respRequestUuid); + }, + timeoutMs, + API_TIMEOUT + ); + + Logger.debug("Sending to DesktopAgent: {}", MessageLogging.summarise(message)); + if (Logger.isPayloadEnabled()) { + Logger.payload("Sending to DesktopAgent: {}", MessageLogging.redact(message)); + } + + + // Wait for post to complete before proceeding to ensure message is recorded + return post(message).thenCompose(v -> promise).thenApply(response -> { + Map resp = (Map) response; + Map payload = (Map) resp.get("payload"); + if (payload != null && payload.get("error") != null) { + throw new RuntimeException((String) payload.get("error")); + } + return response; + }).exceptionally(error -> { + // The stage hands us a CompletionException wrapping the real failure. Rethrowing it + // as-is would add a second wrapper, leaving callers to unwrap twice to reach the + // FDC3 error name they are supposed to match on. + Throwable cause = error instanceof CompletionException && error.getCause() != null + ? error.getCause() + : error; + + if (API_TIMEOUT.equals(cause.getMessage())) { + Logger.error("Timed-out while waiting for {} with requestUuid {}", expectedTypeName, requestUuid); + } + + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + throw new CompletionException(cause); + }); + } + + @Override + public AppIdentifier getAppIdentifier() { + return appIdentifier; + } + + @Override + public SchemaConverter getConverter() { + return converter; + } + + @Override + public abstract CompletionStage disconnect(); +} + diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ContextMetadataMapper.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ContextMetadataMapper.java new file mode 100644 index 00000000..4f4eaf1a --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ContextMetadataMapper.java @@ -0,0 +1,216 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.util; + +import java.time.Instant; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Supplier; + +import org.finos.fdc3.api.metadata.AntiReplayClaims; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DetachedSignature; +import org.finos.fdc3.api.types.AppIdentifier; + +/** + * Maps between DACP wire metadata maps and {@link ContextMetadata}. + */ +public final class ContextMetadataMapper { + + private ContextMetadataMapper() { + } + + /** + * Outbound metadata for DACP request payloads when the app supplied metadata. + * Callers must omit the field entirely when the app did not supply any + * (rather than sending an empty object). + *

+ * Emits only {@code traceId}, {@code signature}, {@code antiReplay} and {@code custom}: the + * {@code AppProvidableContextMetadata} schema declares {@code additionalProperties: false} + * over exactly those fields. Receive-side verification results are not reachable through + * {@link AppProvidableContextMetadata}, so there is nothing further to drop here. + */ + public static Map toWire(AppProvidableContextMetadata metadata) { + return toWire(metadata, false, null); + } + + /** + * Outbound metadata for intent raise requests when the app supplied metadata. + * Prefer omitting the field when metadata is null (Desktop Agent owns traceId generation). + * + * @deprecated Prefer {@link #toWire(AppProvidableContextMetadata)} and omit when null. + */ + @Deprecated + public static Map toWireForIntentRequest( + AppProvidableContextMetadata metadata, + Supplier traceIdSupplier) { + return toWire(metadata, true, traceIdSupplier); + } + + private static Map toWire( + AppProvidableContextMetadata metadata, + boolean ensureTraceId, + Supplier traceIdSupplier) { + if (metadata == null) { + if (ensureTraceId && traceIdSupplier != null) { + Map wire = new LinkedHashMap<>(); + wire.put("traceId", traceIdSupplier.get()); + return wire; + } + return new LinkedHashMap<>(); + } + if (!(metadata instanceof ContextMetadata)) { + throw new IllegalArgumentException("metadata must be ContextMetadata"); + } + ContextMetadata cm = (ContextMetadata) metadata; + Map wire = new LinkedHashMap<>(); + + String traceId = cm.getTraceId(); + if (traceId == null && ensureTraceId && traceIdSupplier != null) { + traceId = traceIdSupplier.get(); + } + if (traceId != null) { + wire.put("traceId", traceId); + } + + DetachedSignature signature = cm.getSignature(); + if (signature != null) { + wire.put("signature", signatureToMap(signature)); + } + + AntiReplayClaims antiReplay = cm.getAntiReplay(); + if (antiReplay != null) { + wire.put("antiReplay", antiReplayToMap(antiReplay)); + } + + Map custom = cm.getCustom(); + if (custom != null) { + wire.put("custom", new LinkedHashMap<>(custom)); + } + + return wire; + } + + /** + * What to record when a received message carries no {@code traceId}. + *

+ * The {@code ContextMetadata} schema makes {@code traceId} required, so something has to be + * supplied. Which fallback is correct depends on the receive path, and each one mirrors the + * reference implementation. + */ + public enum MissingTraceId { + + /** + * Leave it absent, as {@code DefaultContextListener} does. + */ + LEAVE_ABSENT, + + /** + * Record an empty string, as {@code DefaultChannel.getCurrentContext} and intent result + * metadata do. This satisfies the required field while still saying plainly that no + * trace id was received. + */ + EMPTY, + + /** + * Generate one, as {@code DefaultIntentListener} does. Only correct where the app is + * expected to continue a trace it cannot otherwise identify. + */ + GENERATE + } + + public static ContextMetadata fromWire( + Map payloadMetadata, Object messageTimestamp, MissingTraceId missingTraceId) { + return fromWire(payloadMetadata, messageTimestamp, null, missingTraceId); + } + + /** + * Builds listener metadata from wire payload fields and optional message {@code meta} (e.g. event source). + *

+ * A {@code traceId} correlates a message across applications, so one is never invented here + * beyond what {@code missingTraceId} asks for. Generating a fresh identifier on every receive + * path, as this once did, produced trace ids that correlated with nothing and hid the + * difference between a sender that supplied one and a sender that did not. + */ + @SuppressWarnings("unchecked") + public static ContextMetadata fromWire( + Map payloadMetadata, + Object messageTimestamp, + Map messageMeta, + MissingTraceId missingTraceId) { + ContextMetadata metadata = ContextMetadata.fromMap(payloadMetadata); + if (metadata == null) { + metadata = ContextMetadata.appProvidable(); + } + if (metadata.getTimestamp() == null && messageTimestamp != null) { + if (messageTimestamp instanceof Instant) { + metadata.setTimestamp((Instant) messageTimestamp); + } else { + metadata.setTimestamp(Instant.parse(String.valueOf(messageTimestamp))); + } + } + if (metadata.getTraceId() == null || metadata.getTraceId().isEmpty()) { + switch (missingTraceId) { + case GENERATE: + metadata.setTraceId(UUID.randomUUID().toString()); + break; + case EMPTY: + metadata.setTraceId(""); + break; + case LEAVE_ABSENT: + default: + break; + } + } + applyMetaSourceIfAbsent(metadata, messageMeta); + return metadata; + } + + @SuppressWarnings("unchecked") + private static void applyMetaSourceIfAbsent(ContextMetadata metadata, Map messageMeta) { + if (metadata.getSource() != null || messageMeta == null) { + return; + } + Object source = messageMeta.get("source"); + if (source instanceof AppIdentifier) { + metadata.setSource((AppIdentifier) source); + } else if (source instanceof Map) { + metadata.setSource(AppIdentifier.fromMap((Map) source)); + } + } + + private static Map signatureToMap(DetachedSignature signature) { + Map map = new LinkedHashMap<>(); + if (signature.getProtectedHeader() != null) { + map.put("protected", signature.getProtectedHeader()); + } + if (signature.getSignature() != null) { + map.put("signature", signature.getSignature()); + } + return map; + } + + private static Map antiReplayToMap(AntiReplayClaims antiReplay) { + Map map = new LinkedHashMap<>(); + map.put("iat", antiReplay.getIat()); + map.put("exp", antiReplay.getExp()); + map.put("jti", antiReplay.getJti()); + return map; + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/Logger.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/Logger.java new file mode 100644 index 00000000..1300370f --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/Logger.java @@ -0,0 +1,95 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.util; + +import org.slf4j.LoggerFactory; + +/** + * Simple logging utility for the FDC3 Agent Proxy. + *

+ * Log levels are configured through the SLF4J binding (e.g., Logback, Log4j2). + */ +public final class Logger { + + private static final org.slf4j.Logger log = LoggerFactory.getLogger("fdc3.proxy"); + + /** + * Separate logger for full DACP message bodies, which carry application context and, + * during the WSCP handshake, the connection secret. Kept apart from {@link #log} so that + * enabling DEBUG on the proxy does not disclose message contents. + */ + private static final org.slf4j.Logger payloadLog = LoggerFactory.getLogger("fdc3.proxy.payload"); + + private Logger() { + // Utility class + } + + /** + * Whether full message bodies would be recorded. Callers should check this before doing + * the work of redacting and serialising a payload. + * + * @return true if the payload trace logger is enabled + */ + public static boolean isPayloadEnabled() { + return payloadLog.isTraceEnabled(); + } + + /** + * Logs a full message body to the payload trace logger. Callers are responsible for + * redacting sensitive fields first; see + * {@link MessageLogging#redact(Object)}. + */ + public static void payload(String message, Object... args) { + payloadLog.trace(message, args); + } + + public static void debug(String message) { + log.debug(message); + } + + public static void debug(String message, Object... args) { + log.debug(message, args); + } + + public static void info(String message) { + log.info(message); + } + + public static void info(String message, Object... args) { + log.info(message, args); + } + + public static void warn(String message) { + log.warn(message); + } + + public static void warn(String message, Object... args) { + log.warn(message, args); + } + + public static void error(String message) { + log.error(message); + } + + public static void error(String message, Object... args) { + log.error(message, args); + } + + public static void error(String message, Throwable throwable) { + log.error(message, throwable); + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/MessageLogging.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/MessageLogging.java new file mode 100644 index 00000000..e50193c3 --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/MessageLogging.java @@ -0,0 +1,115 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Helpers for logging DACP messages without disclosing credentials or business data. + *

+ * DACP messages carry both the WSCP {@code sharedSecret} and application context such as + * contact and instrument data, so full message bodies are only ever written to the payload + * trace logger (see {@link Logger#payload}). Routine logging uses {@link #summarise} instead. + */ +public final class MessageLogging { + + private static final String REDACTED = ""; + + /** + * Keys whose values must never be logged. {@code sharedSecret} is the WSCP connection + * credential, which the specification requires be kept out of logs. + */ + private static final Set SENSITIVE_KEYS = Set.of("sharedSecret"); + + private MessageLogging() { + // Utility class + } + + /** + * Describes a message by type and correlation id only, omitting its payload. + * + * @param message the DACP message, which may be null + * @return a short description safe to log at DEBUG + */ + @SuppressWarnings("unchecked") + public static String summarise(Map message) { + if (message == null) { + return ""; + } + + Object type = message.get("type"); + StringBuilder description = new StringBuilder(type == null ? "" : type.toString()); + + Object metaValue = message.get("meta"); + if (metaValue instanceof Map) { + Map meta = (Map) metaValue; + appendIfPresent(description, "requestUuid", meta.get("requestUuid")); + appendIfPresent(description, "responseUuid", meta.get("responseUuid")); + appendIfPresent(description, "eventUuid", meta.get("eventUuid")); + appendIfPresent(description, "connectionAttemptUuid", meta.get("connectionAttemptUuid")); + } + + return description.toString(); + } + + private static void appendIfPresent(StringBuilder target, String label, Object value) { + if (value != null) { + target.append(' ').append(label).append('=').append(value); + } + } + + /** + * Copies a message, replacing the value of every sensitive key with a placeholder. + *

+ * The copy is structural only: values that are neither maps nor collections are shared + * with the original, since they are not traversed further. + * + * @param message the DACP message, which may be null + * @return a copy safe to serialise into the payload trace log + */ + public static Object redact(Object message) { + if (message instanceof Map) { + @SuppressWarnings("unchecked") + Map source = (Map) message; + Map copy = new LinkedHashMap<>(source.size()); + for (Map.Entry entry : source.entrySet()) { + if (SENSITIVE_KEYS.contains(entry.getKey())) { + copy.put(entry.getKey(), REDACTED); + } else { + copy.put(entry.getKey(), redact(entry.getValue())); + } + } + return copy; + } + + if (message instanceof Collection) { + Collection source = (Collection) message; + List copy = new ArrayList<>(source.size()); + for (Object element : source) { + copy.add(redact(element)); + } + return copy; + } + + return message; + } +} diff --git a/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ThrowIfUndefined.java b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ThrowIfUndefined.java new file mode 100644 index 00000000..7d8872da --- /dev/null +++ b/fdc3-agent-proxy/src/main/java/org/finos/fdc3/proxy/util/ThrowIfUndefined.java @@ -0,0 +1,74 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.util; + +/** + * Validates that a Desktop Agent's response carried the property the proxy needs. + *

+ * The DACP schemas mark most response payload fields as optional, because a single message type + * covers both success and failure. That means a response can be schema-valid yet still be missing + * the field the caller depends on. Without a check, the proxy would go on to dereference it and + * surface a {@code NullPointerException} rather than an FDC3 error, leaving an application unable + * to tell a faulty Desktop Agent from a genuine failure. + *

+ * This mirrors {@code throwIfUndefined} in the reference implementation: it exists to catch bugs + * in Desktop Agent implementations, so the thrown message is always an FDC3 error name that the + * calling application can match on, while the diagnostic detail goes to the log. + */ +public final class ThrowIfUndefined { + + private ThrowIfUndefined() { + // Utility class + } + + /** + * Throws if {@code property} is absent. + * + * @param property the value taken from the response payload + * @param absentMessage what was expected, logged when the check fails + * @param message the message that was missing the property, logged for diagnosis + * @param absentError the FDC3 error name to report, which becomes the exception message + * @throws RuntimeException carrying {@code absentError} if the property is absent + */ + public static void throwIfUndefined( + Object property, String absentMessage, Object message, String absentError) { + if (property != null) { + return; + } + + Logger.error("{}. DACP message that resulted in the absent property: {}", + absentMessage, MessageLogging.summarise(asMessageMap(message))); + if (Logger.isPayloadEnabled()) { + Logger.payload("Message with the absent property: {}", MessageLogging.redact(message)); + } + + throw new RuntimeException(absentError); + } + + /** + * Adapts a message to the map form {@link MessageLogging#summarise} expects, tolerating the + * typed message objects that some call sites hold. + */ + @SuppressWarnings("unchecked") + private static java.util.Map asMessageMap(Object message) { + if (message instanceof java.util.Map) { + return (java.util.Map) message; + } + return null; + } +} diff --git a/fdc3-agent-proxy/src/main/npm/package-lock.json b/fdc3-agent-proxy/src/main/npm/package-lock.json new file mode 100644 index 00000000..a66f82f8 --- /dev/null +++ b/fdc3-agent-proxy/src/main/npm/package-lock.json @@ -0,0 +1,59 @@ +{ + "name": "fdc3-agent-proxy-test-features", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fdc3-agent-proxy-test-features", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-agent-proxy": "3.0.0-alpha.5" + } + }, + "node_modules/@finos/fdc3-agent-proxy": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-agent-proxy/-/fdc3-agent-proxy-3.0.0-alpha.5.tgz", + "integrity": "sha512-//ra2DNNtCa0n25GO5maoWhsL4PjwjQ7aIi1GONKYpvS+sKAsRoW/J5ZrrI/vfnL4UFxR8X/fajbiVqW9Fv01A==", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-schema": "3.0.0-alpha.5", + "@finos/fdc3-standard": "3.0.0-alpha.5" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@finos/fdc3-context": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-context/-/fdc3-context-3.0.0-alpha.5.tgz", + "integrity": "sha512-VN2LEmWvqLz4xsfXEsqcMNJjxD97/oyh7uPOwHmapoIuc0aW0YS9750tbcCf9GqC3XKnaca+itSW+rhlStJNvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@finos/fdc3-schema": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-schema/-/fdc3-schema-3.0.0-alpha.5.tgz", + "integrity": "sha512-LAKu4HEpQ+UNDco/1ehObiO+QqHoOmGFCP8dk5EerA/2XL0ki6bTFoM0E9ZaGeOQcxz9ifRAJrRDiiYzVi21Bg==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@finos/fdc3-standard": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-standard/-/fdc3-standard-3.0.0-alpha.5.tgz", + "integrity": "sha512-lO9mv61xzimg+uTTBrFodsoF46ve/bAhRJAIcfFowLRz7QohX5M50Gp0zsU1ORLoCTK5jn/TmhyPB/8RR4fIjA==", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-context": "3.0.0-alpha.5" + }, + "engines": { + "node": ">=22" + } + } + } +} diff --git a/fdc3-agent-proxy/src/main/npm/package.json b/fdc3-agent-proxy/src/main/npm/package.json new file mode 100644 index 00000000..092448d1 --- /dev/null +++ b/fdc3-agent-proxy/src/main/npm/package.json @@ -0,0 +1,10 @@ +{ + "name": "fdc3-agent-proxy-test-features", + "version": "1.0.0", + "private": true, + "description": "Pins @finos/fdc3-agent-proxy so the Java Cucumber suite can load the published test/features. Copied into target/npm-work by the Maven build, which then runs 'npm ci' against the committed lockfile.", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-agent-proxy": "3.0.0-alpha.5" + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberHooks.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberHooks.java new file mode 100644 index 00000000..1fd6bea7 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberHooks.java @@ -0,0 +1,64 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy; + +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.Scenario; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.world.CustomWorld; + +/** + * Cucumber hooks for setting up and tearing down test state. + */ +public class CucumberHooks { + + private final CustomWorld world; + + public CucumberHooks(CustomWorld world) { + this.world = world; + } + + /** + * Before each scenario, set the scenario on the world for logging. + */ + @Before + public void beforeScenario(Scenario scenario) { + world.setScenario(scenario); + } + + /** + * Disconnects the messaging created by a scenario. + *

+ * Scenarios register listeners and start timeout tasks through the messaging instance. Left + * connected, those outlive the scenario and can still fire during later ones, so a failure + * appears in whichever scenario happens to be running rather than the one that caused it. + */ + @After + public void afterScenario() { + if (!world.hasMessaging()) { + return; + } + try { + world.getMessaging().disconnect().toCompletableFuture().join(); + } catch (RuntimeException e) { + // Teardown only. Reporting this as a failure would mask the scenario's own result. + Logger.warn("Failed to disconnect test messaging during teardown: {}", e.getMessage()); + } + } +} + diff --git a/client/src/main/java/com/finos/fdc3/client/AppGUIException.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberSpringConfiguration.java similarity index 60% rename from client/src/main/java/com/finos/fdc3/client/AppGUIException.java rename to fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberSpringConfiguration.java index f0e900ff..d59c1158 100644 --- a/client/src/main/java/com/finos/fdc3/client/AppGUIException.java +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/CucumberSpringConfiguration.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,15 @@ * limitations under the License. */ -package com.finos.fdc3.client; +package org.finos.fdc3.proxy; -public class AppGUIException extends RuntimeException -{ +import io.cucumber.spring.CucumberContextConfiguration; +import org.springframework.test.context.ContextConfiguration; -private static final long serialVersionUID = 2513577967801719624L; - -public AppGUIException(String message) -{ - super(message); -} - -public AppGUIException(String message, Throwable t) -{ - super(message, t); +/** + * Cucumber Spring configuration entry point. + */ +@CucumberContextConfiguration +@ContextConfiguration(classes = TestSpringConfig.class) +public class CucumberSpringConfiguration { } - -} \ No newline at end of file diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RaiseIntentOverloadTest.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RaiseIntentOverloadTest.java new file mode 100644 index 00000000..b15e0f1e --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RaiseIntentOverloadTest.java @@ -0,0 +1,225 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.proxy.intents.IntentSupport; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * Guards the arity of the {@code raiseIntent} and {@code raiseIntentForContext} overload sets. + *

+ * TypeScript declares each of these as a single method with trailing optional parameters. Java + * has to express that as overloads, and an earlier arrangement offered two different methods at + * the same arity - for example {@code (intent, context, app)} alongside + * {@code (intent, context, metadata)} - which made {@code raiseIntent("i", context, null)} + * ambiguous and impossible to compile. + *

+ * The calls in {@link #callableShapes} therefore matter at compile time as much as at run time: + * reintroducing a colliding overload would stop this class compiling. The assertions additionally + * confirm that each shorter form pads the remaining arguments with null from the right, rather + * than reordering them. + */ +class RaiseIntentOverloadTest { + + /** + * Records the arguments the proxy forwards to the intent layer, so the tests can assert on + * how each default overload padded its call. + */ + private static final class RecordingIntentSupport implements IntentSupport { + + private String intent; + private Context context; + private AppIdentifier app; + private Boolean newInstance; + private AppProvidableContextMetadata metadata; + private int callCount; + + @Override + public CompletionStage raiseIntent( + String intent, + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + this.intent = intent; + this.context = context; + this.app = app; + this.newInstance = newInstance; + this.metadata = metadata; + this.callCount++; + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage raiseIntentForContext( + Context context, + AppIdentifier app, + Boolean newInstance, + AppProvidableContextMetadata metadata) { + this.intent = null; + this.context = context; + this.app = app; + this.newInstance = newInstance; + this.metadata = metadata; + this.callCount++; + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage findIntent(String intent, Context context, String resultType) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletionStage> findIntentsByContext(Context context, String resultType) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletionStage addIntentListener(String intent, IntentHandler handler) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletionStage addIntentListenerWithContext( + String intent, List contextTypes, IntentHandler handler) { + throw new UnsupportedOperationException(); + } + } + + private RecordingIntentSupport intents; + private DesktopAgent agent; + + private DesktopAgent agent() { + if (agent == null) { + intents = new RecordingIntentSupport(); + agent = new DesktopAgentProxy(null, null, intents, null, List.of()); + } + return agent; + } + + /** + * Every call shape the interface offers. This method is never invoked; it exists so that the + * compiler resolves each shape, which is what regressed previously. + */ + @SuppressWarnings("unused") + private static void callableShapes(DesktopAgent agent, Context context, AppIdentifier app, + AppProvidableContextMetadata metadata) { + agent.raiseIntent("StartChat", context); + agent.raiseIntent("StartChat", context, app); + agent.raiseIntent("StartChat", context, app, true); + agent.raiseIntent("StartChat", context, app, true, metadata); + + // The shape that did not compile before the overloads were collapsed. + agent.raiseIntent("StartChat", context, null); + agent.raiseIntent("StartChat", context, null, null, metadata); + + agent.raiseIntentForContext(context); + agent.raiseIntentForContext(context, app); + agent.raiseIntentForContext(context, app, true); + agent.raiseIntentForContext(context, app, true, metadata); + + agent.raiseIntentForContext(context, null); + agent.raiseIntentForContext(context, null, null, metadata); + } + + @Test + @DisplayName("raiseIntent with an explicitly null app resolves to a single overload") + void nullAppIsUnambiguous() { + Context context = new Context("fdc3.instrument"); + + agent().raiseIntent("StartChat", context, null); + + assertEquals(1, intents.callCount); + assertEquals("StartChat", intents.intent); + assertSame(context, intents.context); + assertNull(intents.app); + assertNull(intents.newInstance); + assertNull(intents.metadata); + } + + @Test + @DisplayName("Shorter raiseIntent overloads pad the trailing arguments with null") + void shorterOverloadsPadFromTheRight() { + Context context = new Context("fdc3.instrument"); + AppIdentifier app = new AppIdentifier("target-app"); + + agent().raiseIntent("StartChat", context); + assertNull(intents.app); + assertNull(intents.newInstance); + assertNull(intents.metadata); + + agent().raiseIntent("StartChat", context, app); + assertSame(app, intents.app); + assertNull(intents.newInstance); + assertNull(intents.metadata); + + agent().raiseIntent("StartChat", context, app, true); + assertSame(app, intents.app); + assertEquals(Boolean.TRUE, intents.newInstance); + assertNull(intents.metadata); + } + + @Test + @DisplayName("Metadata is only reachable through the full-arity raiseIntent") + void metadataReachesTheIntentLayer() { + Context context = new Context("fdc3.instrument"); + AppProvidableContextMetadata metadata = new ContextMetadata(); + + agent().raiseIntent("StartChat", context, null, null, metadata); + + assertSame(metadata, intents.metadata); + assertNull(intents.app); + assertNull(intents.newInstance); + } + + @Test + @DisplayName("raiseIntentForContext overloads pad the trailing arguments with null") + void raiseIntentForContextPadsFromTheRight() { + Context context = new Context("fdc3.instrument"); + AppIdentifier app = new AppIdentifier("target-app"); + + agent().raiseIntentForContext(context); + assertSame(context, intents.context); + assertNull(intents.app); + assertNull(intents.newInstance); + assertNull(intents.metadata); + + agent().raiseIntentForContext(context, app, true); + assertSame(app, intents.app); + assertEquals(Boolean.TRUE, intents.newInstance); + assertNull(intents.metadata); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RunCucumberTest.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RunCucumberTest.java new file mode 100644 index 00000000..76a67be7 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/RunCucumberTest.java @@ -0,0 +1,43 @@ +/* + * Copyright FINOS and Contributors to the FDC3 project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.finos.fdc3.proxy; + +import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.IncludeEngines; +import org.junit.platform.suite.api.Suite; + +import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.OBJECT_FACTORY_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME; + +/** + * JUnit Platform Suite entry point so Maven Surefire discovers Cucumber scenarios, + * reports an accurate test count, and fails the build on scenario failures. + * + * @see cucumber-junit-platform-engine + */ +@Suite +@IncludeEngines("cucumber") +@ConfigurationParameter(key = FEATURES_PROPERTY_NAME, value = "classpath:features") +@ConfigurationParameter( + key = GLUE_PROPERTY_NAME, + value = "org.finos.fdc3.proxy,org.finos.fdc3.proxy.steps,org.finos.fdc3.proxy.world,org.finos.cucumbertestingsteps.steps") +@ConfigurationParameter(key = OBJECT_FACTORY_PROPERTY_NAME, value = "io.cucumber.spring.SpringFactory") +@ConfigurationParameter( + key = PLUGIN_PROPERTY_NAME, + value = "pretty,summary,junit:target/cucumber-reports/cucumber.xml,html:target/cucumber-reports/cucumber.html") +public class RunCucumberTest {} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/TestSpringConfig.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/TestSpringConfig.java new file mode 100644 index 00000000..1d8537d7 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/TestSpringConfig.java @@ -0,0 +1,64 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy; + +import org.finos.fdc3.proxy.world.CustomWorld; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.ScopedProxyMode; + +import io.cucumber.spring.ScenarioScope; +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * Spring configuration for Cucumber tests. + * + * This configuration ensures that: + * 1. CustomWorld is used as the shared world instance + * 2. PropsWorld injections receive the CustomWorld instance + */ +@Configuration +@ComponentScan(basePackages = { + "org.finos.fdc3.proxy.steps", + "org.finos.cucumbertestingsteps.steps" +}) +public class TestSpringConfig { + + /** + * Create CustomWorld as a scenario-scoped bean. + */ + @Bean + @ScenarioScope(proxyMode = ScopedProxyMode.NO) + public CustomWorld customWorld() { + return new CustomWorld(); + } + + /** + * Provide CustomWorld as the implementation for PropsWorld. + * This ensures GenericSteps (which depends on PropsWorld) gets + * the same instance as AgentSteps (which depends on CustomWorld). + */ + @Bean + @Primary + @ScenarioScope(proxyMode = ScopedProxyMode.NO) + public PropsWorld propsWorld(CustomWorld customWorld) { + return customWorld; + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SchemaMatchers.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SchemaMatchers.java new file mode 100644 index 00000000..c8e88506 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SchemaMatchers.java @@ -0,0 +1,211 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.schema; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.jxpath.JXPathNotFoundException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.ValidationMessage; + +import org.finos.cucumbertestingsteps.support.MatchingUtils; +import org.finos.cucumbertestingsteps.support.RowFieldMatcher; +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * Registers the {@code matches_type} table column matcher for FDC3 DACP messages. + * Java equivalent of {@code @finos/fdc3-schema/test/fdc3SchemaMatchers.ts}. + */ +public final class Fdc3SchemaMatchers { + + private static final String MATCHES_TYPE_SUFFIX = "matches_type"; + private static final String PROTECTED_SUFFIX = ".protected"; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + /** Browser WCP and native WSCP use different goodbye type names for the same disconnect. */ + private static final Set GOODBYE_SCHEMA_IDS = Set.of("WCP6Goodbye", "WSCPGoodbye"); + + private static final RowFieldMatcher MATCHES_TYPE_MATCHER = new RowFieldMatcher() { + @Override + public boolean matchesField(String field) { + return field.endsWith(MATCHES_TYPE_SUFFIX); + } + + @Override + @SuppressWarnings("unchecked") + public boolean matchField(PropsWorld world, String field, String schemaId, Object rowData) { + String path = MatchingUtils.pathForFieldSuffix(field, MATCHES_TYPE_SUFFIX); + if (path == null) { + return false; + } + + Object value = valueAtPath(rowData, path); + + Map schemas = (Map) world.get("schemas"); + if (schemas == null) { + world.log("Schemas not loaded — call Given schemas loaded first"); + return false; + } + + String resolvedSchemaId = resolveGoodbyeSchemaId(schemaId, value); + JsonSchema schema = schemas.get(resolvedSchemaId); + if (schema == null) { + throw new IllegalStateException("No schema found for " + resolvedSchemaId); + } + + try { + JsonNode jsonValue = OBJECT_MAPPER.valueToTree(value); + Set errors = schema.validate(jsonValue); + if (errors.isEmpty()) { + return true; + } + String messages = errors.stream() + .map(ValidationMessage::getMessage) + .collect(Collectors.joining("; ")); + world.log("Schema validation failed for " + resolvedSchemaId + ": " + messages); + return false; + } catch (Exception e) { + world.log("Schema validation error for " + resolvedSchemaId + ": " + e.getMessage()); + return false; + } + } + }; + + /** + * JXPath cannot resolve JavaBean paths ending in {@code protected} (language keyword). FDC3 metadata + * uses {@code @JsonProperty("protected")} on {@code getProtectedHeader()}, so table columns like + * {@code signature.protected} need an alternate lookup via {@code protectedHeader}. + */ + private static final RowFieldMatcher SIGNATURE_PROTECTED_MATCHER = new RowFieldMatcher() { + @Override + public boolean matchesField(String field) { + return field.endsWith(PROTECTED_SUFFIX); + } + + @Override + public boolean matchField(PropsWorld world, String field, String expected, Object rowData) { + Object found = resolveProtectedField(rowData, field); + Object resolved = MatchingUtils.handleResolve(expected, world); + if (found == null && resolved == null) { + return true; + } + if (found == null || resolved == null) { + world.log(String.format("Match failed on %s: '%s' vs '%s'", field, found, resolved)); + return false; + } + boolean matches = Objects.equals(found, resolved) + || Objects.equals(String.valueOf(found), String.valueOf(resolved)); + if (!matches) { + world.log(String.format("Match failed on %s: '%s' vs '%s'", field, found, resolved)); + } + return matches; + } + }; + + static { + MatchingUtils.registerFieldMatcher(MATCHES_TYPE_MATCHER); + MatchingUtils.registerFieldMatcher(SIGNATURE_PROTECTED_MATCHER); + } + + private Fdc3SchemaMatchers() { + } + + public static void registerFdc3SchemaMatchers() { + // Matcher registered in static initializer (same pattern as TypeScript side-effect import). + } + + /** + * Feature files always name the browser goodbye ({@code WCP6Goodbye}). Java posts the WSCP + * equivalent ({@code WSCPGoodbye}). When either goodbye id is expected and the message carries + * the other, validate against the schema that matches the posted type. + */ + @SuppressWarnings("unchecked") + private static String resolveGoodbyeSchemaId(String schemaId, Object value) { + if (!GOODBYE_SCHEMA_IDS.contains(schemaId) || !(value instanceof Map)) { + return schemaId; + } + Object type = ((Map) value).get("type"); + if (type instanceof String && GOODBYE_SCHEMA_IDS.contains(type)) { + return (String) type; + } + return schemaId; + } + + private static Object valueAtPath(Object data, String path) { + if (path.isEmpty()) { + return data; + } + try { + JXPathContext context = JXPathContext.newContext(data); + context.setLenient(true); + String xpathName = "/" + path.replaceAll("\\.", "/"); + xpathName = xpathName.replaceAll("(/[^/]+)/length$", "count($1)"); + return context.getValue(xpathName); + } catch (JXPathNotFoundException e) { + return null; + } + } + + private static Object resolveProtectedField(Object data, String field) { + Object found = valueAtPath(data, field); + if (found != null) { + return found; + } + + String protectedHeaderPath = + field.substring(0, field.length() - PROTECTED_SUFFIX.length()) + ".protectedHeader"; + found = valueAtPath(data, protectedHeaderPath); + if (found != null) { + return found; + } + + String signaturePath = field.substring(0, field.length() - PROTECTED_SUFFIX.length()); + return protectedValueFromSignature(valueAtPath(data, signaturePath)); + } + + @SuppressWarnings("unchecked") + private static Object protectedValueFromSignature(Object signature) { + if (signature == null) { + return null; + } + if (signature instanceof Map) { + Map map = (Map) signature; + Object value = map.get("protected"); + if (value == null) { + value = map.get("protectedHeader"); + } + return value; + } + try { + Map map = OBJECT_MAPPER.convertValue(signature, Map.class); + Object value = map.get("protected"); + if (value == null) { + value = map.get("protectedHeader"); + } + return value; + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SignatureMatcherTest.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SignatureMatcherTest.java new file mode 100644 index 00000000..aa74748c --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/Fdc3SignatureMatcherTest.java @@ -0,0 +1,74 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.schema; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.finos.cucumbertestingsteps.support.MatchingUtils; +import org.finos.cucumbertestingsteps.world.PropsWorld; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DetachedSignature; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.ContextWithMetadata; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class Fdc3SignatureMatcherTest { + + @BeforeAll + static void registerMatchers() { + Fdc3SchemaMatchers.registerFdc3SchemaMatchers(); + } + + @Test + void matchesSignatureProtectedOnContextMetadata() { + ContextMetadata metadata = ContextMetadata.appProvidable(); + metadata.setSource(new AppIdentifier("cucumber-app", "cucumber-instance")); + DetachedSignature signature = new DetachedSignature(); + signature.setProtectedHeader("test-sig (protected part)"); + signature.setSignature("test-sig (signature part)"); + metadata.setSignature(signature); + + Map row = new LinkedHashMap<>(); + row.put("signature.signature", "test-sig (signature part)"); + row.put("signature.protected", "test-sig (protected part)"); + + PropsWorld world = new PropsWorld(); + assertTrue(MatchingUtils.doesRowMatch(world, row, metadata)); + } + + @Test + void matchesMetadataSignatureProtectedOnContextWithMetadata() { + ContextMetadata metadata = ContextMetadata.appProvidable(); + DetachedSignature signature = new DetachedSignature(); + signature.setProtectedHeader("test-signature (protected part)"); + signature.setSignature("test-signature (signature part)"); + metadata.setSignature(signature); + + ContextWithMetadata result = new ContextWithMetadata(null, metadata); + + Map row = new LinkedHashMap<>(); + row.put("metadata.signature.signature", "test-signature (signature part)"); + row.put("metadata.signature.protected", "test-signature (protected part)"); + + PropsWorld world = new PropsWorld(); + assertTrue(MatchingUtils.doesRowMatch(world, row, result)); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/LoadSchemas.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/LoadSchemas.java new file mode 100644 index 00000000..3aabd6f9 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/LoadSchemas.java @@ -0,0 +1,228 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.schema; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SpecVersion; + +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * Loads FDC3 JSON schemas from local files into the test world. + * Java equivalent of {@code @finos/fdc3-schema/test/loadSchemas.ts} (Ajv {@code addSchema} pool). + */ +public final class LoadSchemas { + + private static final String SCHEMA_BASE = "https://fdc3.finos.org/schemas/next/api/"; + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static final String[] API_SCHEMA_LOAD_ORDER = { + "api.schema.json", + "common.schema.json", + "appRequest.schema.json", + "agentRequest.schema.json", + "agentResponse.schema.json", + "appResponse.schema.json", + }; + + private static volatile JsonSchemaFactory schemaFactory; + /** Compiled validators keyed by short schema id (e.g. {@code broadcastRequest}). */ + private static volatile Map schemaValidators; + + private LoadSchemas() { + } + + public static void loadSchemasIntoWorld(PropsWorld world) throws IOException { + if (world.get("schemas") != null) { + return; + } + world.set("schemas", loadSchemaValidators()); + world.set("jsonSchemaFactory", schemaFactory); + } + + public static Map loadSchemaValidators() throws IOException { + Map cached = schemaValidators; + if (cached != null) { + return cached; + } + synchronized (LoadSchemas.class) { + if (schemaValidators != null) { + return schemaValidators; + } + Path apiDir = resolveApiSchemaDirectory(); + if (apiDir == null) { + throw new IllegalStateException( + "API schemas not found at " + SCHEMA_WORK_DIR.resolve("api") + + ". Build fdc3-schema first, which populates schema-work with the" + + " npm-published schemas plus the unreleased overlay. Building" + + " this module alone against a cleaned fdc3-schema/target is not" + + " enough."); + } + + Path contextSchema = resolveContextSchemaFile(); + if (contextSchema == null) { + throw new IllegalStateException( + "Context schema not found at " + + SCHEMA_WORK_DIR.resolve("context/context.schema.json") + + ". Build fdc3-schema first."); + } + + Map schemasByIri = loadSchemaDocuments(apiDir, contextSchema); + + JsonSchemaFactory factory = JsonSchemaFactory.builder( + JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) + .schemaLoaders(loaders -> loaders.schemas(schemasByIri)) + .build(); + + Map validators = new HashMap<>(); + for (Path file : orderSchemaFiles(apiDir)) { + JsonNode node = MAPPER.readTree(file.toFile()); + String shortId = schemaIdFromFile(node, file.getFileName().toString()); + if (node.has("$id")) { + validators.put(shortId, factory.getSchema(SchemaLocation.of(node.get("$id").asText()))); + } + } + + schemaFactory = factory; + schemaValidators = Collections.unmodifiableMap(validators); + return schemaValidators; + } + } + + public static String schemaUri(String schemaId) { + return SCHEMA_BASE + schemaId + ".schema.json"; + } + + /** The directory the API schemas were loaded from, or {@code null} if none was found. */ + public static Path apiSchemaDirectory() { + return resolveApiSchemaDirectory(); + } + + /** + * A validator for a named definition inside {@code api.schema.json}, e.g. + * {@code AppProvidableContextMetadata}. + */ + public static JsonSchema definitionValidator(String definitionName) throws IOException { + loadSchemaValidators(); + return schemaFactory.getSchema( + SchemaLocation.of(SCHEMA_BASE + "api.schema.json#/definitions/" + definitionName)); + } + + private static Map loadSchemaDocuments(Path apiDir, Path contextSchemaFile) throws IOException { + Map schemasByIri = new HashMap<>(); + + for (Path file : orderSchemaFiles(apiDir)) { + String content = Files.readString(file); + JsonNode node = MAPPER.readTree(content); + String filename = file.getFileName().toString(); + schemasByIri.put(filename, content); + if (node.has("$id")) { + schemasByIri.put(node.get("$id").asText(), content); + } + schemasByIri.put(file.toUri().toString(), content); + } + + if (contextSchemaFile != null && Files.exists(contextSchemaFile)) { + String content = Files.readString(contextSchemaFile); + JsonNode node = MAPPER.readTree(content); + schemasByIri.put("../context/context.schema.json", content); + schemasByIri.put(contextSchemaFile.toUri().toString(), content); + if (node.has("$id")) { + schemasByIri.put(node.get("$id").asText(), content); + } + } + + return schemasByIri; + } + + private static List orderSchemaFiles(Path apiDir) throws IOException { + List ordered = new java.util.ArrayList<>(); + Set seen = new LinkedHashSet<>(); + + for (String name : API_SCHEMA_LOAD_ORDER) { + Path p = apiDir.resolve(name); + if (Files.exists(p)) { + ordered.add(p); + seen.add(name); + } + } + + try (Stream files = Files.list(apiDir)) { + ordered.addAll(files.filter(p -> p.toString().endsWith(".json")) + .filter(p -> !seen.contains(p.getFileName().toString())) + .sorted(Comparator.comparing(p -> p.getFileName().toString())) + .collect(Collectors.toList())); + } + return ordered; + } + + /** + * The directory the {@code fdc3-schema} build populates with the npm-published schemas and + * then the unreleased overlay on top. It is deliberately the only location consulted. + *

+ * Earlier versions searched a list of fallbacks: a sibling checkout of the FDC3 monorepo, + * and the raw npm download under {@code npm-work/node_modules}. Both were harmful, because + * a test that cannot find the schemas it was written against does not fail — it silently + * validates against a different set. The npm download in particular has the overlay + * missing by construction, so schemas carrying unreleased fields such as + * {@code raiseIntentRequest.newInstance} appear not to permit them, and conformance results + * then depend on whether {@code fdc3-schema} happened to be rebuilt. Resolving one path and + * failing loudly is what makes these tests mean anything. + */ + private static final Path SCHEMA_WORK_DIR = Paths.get("../fdc3-schema/target/schema-work"); + + private static Path resolveApiSchemaDirectory() { + Path apiDir = SCHEMA_WORK_DIR.resolve("api"); + return Files.isDirectory(apiDir) ? apiDir.normalize() : null; + } + + /** Locates the context schema, from the same single source as the API schemas. */ + private static Path resolveContextSchemaFile() { + Path contextSchema = SCHEMA_WORK_DIR.resolve("context/context.schema.json"); + return Files.isRegularFile(contextSchema) ? contextSchema.normalize() : null; + } + + private static String schemaIdFromFile(JsonNode schemaJson, String filename) { + if (schemaJson.has("$id")) { + String id = schemaJson.get("$id").asText(); + if (id.startsWith(SCHEMA_BASE)) { + return id.substring(SCHEMA_BASE.length()).replace(".schema.json", ""); + } + return id; + } + return filename.replace(".schema.json", "").replace(".json", ""); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/MetadataSchemaConformanceTest.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/MetadataSchemaConformanceTest.java new file mode 100644 index 00000000..553e735c --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/schema/MetadataSchemaConformanceTest.java @@ -0,0 +1,222 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.schema; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.ValidationMessage; + +import org.finos.fdc3.api.metadata.AntiReplayClaims; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DesktopAgentProvidableContextMetadata; +import org.finos.fdc3.api.metadata.DetachedSignature; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.util.ContextMetadataMapper; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Guards the hand-written metadata types in {@code fdc3-standard} against the DACP schemas. + *

+ * {@code ContextRoundTripTest} does this for context types, which are generated from their + * schemas and so cannot drift. The metadata types are hand-written, so nothing previously + * stopped a field being added to (or dropped from) the Java API without a matching schema + * change. These tests close that gap in both directions: + *

    + *
  • the property names the Java interfaces expose must equal the schema's properties;
  • + *
  • everything a caller can set on outbound metadata must survive + * {@link ContextMetadataMapper#toWire} and validate against the schema.
  • + *
+ */ +class MetadataSchemaConformanceTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static JsonNode apiSchema; + + /** + * Fails rather than skips when the schemas are absent. + *

+ * This test exists to catch drift between the hand-written metadata types and the schemas + * that define them. Skipping when it cannot find the schemas would make that drift invisible + * exactly when the check matters: a green build would say the types conform when nothing had + * been compared at all. + */ + @BeforeAll + static void loadApiSchema() throws IOException { + Path apiDir = LoadSchemas.apiSchemaDirectory(); + assertNotNull(apiDir, + "API schemas not found. Run 'mvn install' in fdc3-schema before running these tests."); + + Path apiSchemaFile = apiDir.resolve("api.schema.json"); + assertTrue(Files.isRegularFile(apiSchemaFile), () -> "api.schema.json not found in " + apiDir); + + apiSchema = MAPPER.readTree(apiSchemaFile.toFile()); + } + + @Test + @DisplayName("AppProvidableContextMetadata exposes exactly the properties its schema allows") + void appProvidableMetadataMatchesSchema() { + assertPropertiesMatch("AppProvidableContextMetadata", javaProperties(AppProvidableContextMetadata.class)); + } + + @Test + @DisplayName("ContextMetadata exposes exactly the properties its schema allows") + void contextMetadataMatchesSchema() { + Set javaProperties = new LinkedHashSet<>(javaProperties(AppProvidableContextMetadata.class)); + javaProperties.addAll(javaProperties(DesktopAgentProvidableContextMetadata.class)); + assertPropertiesMatch("ContextMetadata", javaProperties); + } + + @Test + @DisplayName("Everything settable on outbound metadata reaches the wire and validates") + void outboundMetadataSurvivesToWireAndValidates() throws IOException { + ContextMetadata metadata = ContextMetadata.appProvidable(); + + // Populate every field reachable through the outbound-facing interface. + AppProvidableContextMetadata outbound = metadata; + outbound.setTraceId("trace-1"); + DetachedSignature signature = new DetachedSignature(); + signature.setProtectedHeader("protected-header"); + signature.setSignature("signature-value"); + outbound.setSignature(signature); + outbound.setAntiReplay(new AntiReplayClaims(1_700_000_000L, 1_700_003_600L, "nonce-1")); + Map custom = new LinkedHashMap<>(); + custom.put("vendorField", "vendor-value"); + outbound.setCustom(custom); + + Map wire = ContextMetadataMapper.toWire(outbound); + + // Nothing a caller can set may be silently dropped on the way to the wire. + assertEquals(javaProperties(AppProvidableContextMetadata.class), new LinkedHashSet<>(wire.keySet()), + "Fields settable via AppProvidableContextMetadata but missing from the wire payload are " + + "silently dropped; either emit them in ContextMetadataMapper.toWire or remove " + + "them from the outbound interface"); + + JsonSchema schema = LoadSchemas.definitionValidator("AppProvidableContextMetadata"); + Set errors = schema.validate(MAPPER.valueToTree(wire)); + assertTrue(errors.isEmpty(), () -> "Outbound metadata failed schema validation: " + + errors.stream().map(ValidationMessage::getMessage).collect(Collectors.joining("; "))); + } + + @Test + @DisplayName("Inbound metadata round-trips back to an equivalent wire payload") + void inboundMetadataRoundTrips() throws IOException { + Map signature = new LinkedHashMap<>(); + signature.put("protected", "protected-header"); + signature.put("signature", "signature-value"); + Map antiReplay = new LinkedHashMap<>(); + antiReplay.put("iat", 1_700_000_000L); + antiReplay.put("exp", 1_700_003_600L); + antiReplay.put("jti", "nonce-1"); + Map custom = new LinkedHashMap<>(); + custom.put("vendorField", "vendor-value"); + + Map incoming = new LinkedHashMap<>(); + incoming.put("traceId", "trace-1"); + incoming.put("signature", signature); + incoming.put("antiReplay", antiReplay); + incoming.put("custom", custom); + + ContextMetadata metadata = ContextMetadataMapper.fromWire( + incoming, Instant.now(), ContextMetadataMapper.MissingTraceId.LEAVE_ABSENT); + metadata.setSource(new AppIdentifier("app-1", "instance-1")); + + assertEquals("trace-1", metadata.getTraceId()); + assertEquals("protected-header", metadata.getSignature().getProtectedHeader()); + assertEquals("nonce-1", metadata.getAntiReplay().getJti()); + + // Round-trip back out and confirm it still satisfies the outbound schema. + Map wire = ContextMetadataMapper.toWire(metadata); + assertEquals(incoming.keySet(), wire.keySet(), "Round-tripped metadata lost or gained fields"); + + JsonSchema schema = LoadSchemas.definitionValidator("AppProvidableContextMetadata"); + Set errors = schema.validate(MAPPER.valueToTree(wire)); + assertTrue(errors.isEmpty(), () -> "Round-tripped metadata failed schema validation: " + + errors.stream().map(ValidationMessage::getMessage).collect(Collectors.joining("; "))); + } + + private void assertPropertiesMatch(String definitionName, Collection javaProperties) { + Set schemaProperties = schemaProperties(definitionName); + Set inJavaOnly = new TreeSet<>(javaProperties); + inJavaOnly.removeAll(schemaProperties); + Set inSchemaOnly = new TreeSet<>(schemaProperties); + inSchemaOnly.removeAll(javaProperties); + + assertTrue(inJavaOnly.isEmpty() && inSchemaOnly.isEmpty(), + () -> "Java metadata types have drifted from api.schema.json#/definitions/" + definitionName + + "\n exposed by Java but absent from the schema: " + inJavaOnly + + "\n declared in the schema but missing from Java: " + inSchemaOnly); + } + + private Set schemaProperties(String definitionName) { + JsonNode definition = apiSchema.path("definitions").path(definitionName); + assertTrue(definition.isObject(), "api.schema.json has no definition named " + definitionName); + Set properties = new LinkedHashSet<>(); + definition.path("properties").fieldNames().forEachRemaining(properties::add); + return properties; + } + + /** + * The JSON property names an interface exposes, derived from its getters (including + * inherited ones), honouring {@link JsonProperty} overrides. + */ + private static Set javaProperties(Class type) { + Set properties = new LinkedHashSet<>(); + for (Method method : type.getMethods()) { + if (method.getParameterCount() != 0 || method.getDeclaringClass() == Object.class) { + continue; + } + String name = method.getName(); + String property; + if (name.startsWith("get") && name.length() > 3) { + property = name.substring(3); + } else if (name.startsWith("is") && name.length() > 2) { + property = name.substring(2); + } else { + continue; + } + JsonProperty annotation = method.getAnnotation(JsonProperty.class); + if (annotation != null && !annotation.value().isEmpty()) { + properties.add(annotation.value()); + } else { + properties.add(Character.toLowerCase(property.charAt(0)) + property.substring(1)); + } + } + return properties; + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/AgentSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/AgentSteps.java new file mode 100644 index 00000000..c4e498ed --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/AgentSteps.java @@ -0,0 +1,99 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.ui.Connectable; +import org.finos.fdc3.proxy.DesktopAgentProxy; +import org.finos.fdc3.proxy.apps.DefaultAppSupport; +import org.finos.fdc3.proxy.channels.DefaultChannelSupport; +import org.finos.fdc3.proxy.heartbeat.DefaultHeartbeatSupport; +import org.finos.fdc3.proxy.intents.DefaultIntentSupport; +import org.finos.fdc3.proxy.support.SimpleChannelSelector; +import org.finos.fdc3.proxy.support.SimpleIntentResolver; +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.world.CustomWorld; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; + +/** + * Agent step definitions for agent-proxy tests. + */ +public class AgentSteps { + + private final CustomWorld world; + + public AgentSteps(CustomWorld world) { + this.world = world; + } + + @Given("A Desktop Agent in {string}") + public void aDesktopAgentIn(String field) throws Exception { + createDesktopAgent(field, null); + } + + @Given("A Desktop Agent in {string} that puts apps on channel {string}") + public void aDesktopAgentInThatPutsAppsOnChannel(String field, String channelId) throws Exception { + createDesktopAgent(field, channelId); + } + + private void createDesktopAgent(String field, String initialChannelId) throws Exception { + if (!world.hasMessaging()) { + @SuppressWarnings("unchecked") + Map> channelState = (Map>) world.get(ChannelSteps.CHANNEL_STATE); + world.setMessaging(new TestMessaging(channelState != null ? channelState : new HashMap<>(), initialChannelId)); + } + + TestMessaging messaging = world.getMessaging(); + + // Using short timeouts to avoid extending tests unnecessarily + DefaultChannelSupport cs = new DefaultChannelSupport(messaging, new SimpleChannelSelector(world), 1500); + DefaultHeartbeatSupport hs = new DefaultHeartbeatSupport(messaging, 30000); + DefaultIntentSupport is = new DefaultIntentSupport(messaging, new SimpleIntentResolver(world), 1500, 3000); + DefaultAppSupport as = new DefaultAppSupport(messaging, 1500, 3000); + + List connectables = new ArrayList<>(); + connectables.add(hs); + connectables.add(cs); + + DesktopAgentProxy da = new DesktopAgentProxy(hs, cs, is, as, connectables); + da.connect().toCompletableFuture().get(); + + world.set(field, da); + world.set("result", null); + } + + @When("messaging receives a heartbeat event") + public void messagingReceivesHeartbeatEvent() { + Map message = new HashMap<>(); + message.put("type", "heartbeatEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("timestamp", java.time.Instant.now().toString()); + message.put("payload", payload); + + world.getMessaging().receive(message, null); + } + +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSelectorSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSelectorSteps.java new file mode 100644 index 00000000..dfcf3d26 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSelectorSteps.java @@ -0,0 +1,100 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.ui.Connectable; +import org.finos.fdc3.proxy.DesktopAgentProxy; +import org.finos.fdc3.proxy.apps.DefaultAppSupport; +import org.finos.fdc3.proxy.channels.DefaultChannelSupport; +import org.finos.fdc3.proxy.heartbeat.DefaultHeartbeatSupport; +import org.finos.fdc3.proxy.intents.DefaultIntentSupport; +import org.finos.fdc3.proxy.support.SimpleChannelSelector; +import org.finos.fdc3.proxy.support.SimpleIntentResolver; +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.world.CustomWorld; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; + +/** + * Cucumber step definitions for channel selector tests. + */ +public class ChannelSelectorSteps { + + private final CustomWorld world; + + public ChannelSelectorSteps(CustomWorld world) { + this.world = world; + } + + @Given("A Channel Selector in {string} and a Desktop Agent in {string}") + public void aChannelSelectorAndDesktopAgent(String selectorField, String daField) throws Exception { + if (!world.hasMessaging()) { + @SuppressWarnings("unchecked") + Map> channelState = (Map>) world.get(ChannelSteps.CHANNEL_STATE); + world.setMessaging(new TestMessaging(channelState != null ? channelState : new HashMap<>())); + } + + TestMessaging messaging = world.getMessaging(); + SimpleChannelSelector ts = new SimpleChannelSelector(world); + world.set(selectorField, ts); + + // Create the DesktopAgentProxy with the test channel selector + DefaultChannelSupport cs = new DefaultChannelSupport(messaging, ts, 1500); + DefaultHeartbeatSupport hs = new DefaultHeartbeatSupport(messaging, 30000); + DefaultIntentSupport is = new DefaultIntentSupport(messaging, new SimpleIntentResolver(world), 1500, 3000); + DefaultAppSupport as = new DefaultAppSupport(messaging, 1500, 3000); + + List connectables = new ArrayList<>(); + connectables.add(hs); + + DesktopAgentProxy da = new DesktopAgentProxy(hs, cs, is, as, connectables); + da.connect().toCompletableFuture().get(); + + world.set(daField, da); + world.set("result", null); + + // populate the channel selector + List userChannels = cs.getUserChannels().toCompletableFuture().get(); + ts.updateChannel(null, userChannels); + } + + @When("The first channel is selected via the channel selector in {string}") + public void theFirstChannelIsSelected(String selectorField) { + SimpleChannelSelector selector = (SimpleChannelSelector) world.get(selectorField); + selector.selectFirstChannel(); + } + + @When("The second channel is selected via the channel selector in {string}") + public void theSecondChannelIsSelected(String selectorField) { + SimpleChannelSelector selector = (SimpleChannelSelector) world.get(selectorField); + selector.selectSecondChannel(); + } + + @When("The channel is deselected via the channel selector in {string}") + public void theChannelIsDeselected(String selectorField) { + SimpleChannelSelector selector = (SimpleChannelSelector) world.get(selectorField); + selector.deselectChannel(); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSteps.java new file mode 100644 index 00000000..fadaca60 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/ChannelSteps.java @@ -0,0 +1,575 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import static org.finos.cucumbertestingsteps.support.MatchingUtils.handleResolve; +import static org.finos.cucumbertestingsteps.support.MatchingUtils.matchData; + +import java.lang.reflect.InvocationTargetException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DetachedSignature; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.FDC3Event; +import org.finos.fdc3.proxy.support.ContextMap; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.world.CustomWorld; + + +import io.cucumber.datatable.DataTable; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; + +/** + * Cucumber step definitions for channel-related tests. + */ +public class ChannelSteps { + + public static final String CHANNEL_STATE = "CHANNEL_STATE"; + + private final CustomWorld world; + + public ChannelSteps(CustomWorld world) { + this.world = world; + } + + @Given("{string} is a {string} context") + public void isAContext(String field, String type) { + world.set(field, ContextMap.get(type)); + } + + @Given("{string} is an array of context types {string}") + public void isAnArrayOfContextTypes(String field, String types) { + List list = new ArrayList<>(); + for (String t : types.split(",")) { + list.add(t.trim()); + } + world.set(field, list); + } + + @Given("{string} is an array of context types with null {string}") + public void isAnArrayOfContextTypesWithNull(String field, String types) { + List list = new ArrayList<>(); + for (String t : types.split(",")) { + String trimmed = t.trim(); + list.add("{null}".equals(trimmed) ? null : trimmed); + } + world.set(field, list); + } + + @Given("{string} is an empty array") + public void isAnEmptyArray(String field) { + world.set(field, new ArrayList<>()); + } + + @Given("{string} is an app-provided metadata object") + public void isAnAppProvidedMetadataObject(String field) { + ContextMetadata metadata = ContextMetadata.appProvidable(); + metadata.setTraceId("app-trace-id"); + metadata.setSignature(new DetachedSignature("app-protected", "app-signature")); + metadata.setCustom(Map.of("region", "EMEA")); + world.set(field, metadata); + } + + @Given("the next getCurrentContext response has payload {string}") + public void theNextGetCurrentContextResponseHasPayload(String shape) { + Context context = ContextMap.get("fdc3.instrument"); + Map metadata = new HashMap<>(); + Map source = new HashMap<>(); + source.put("appId", "test-app"); + source.put("instanceId", "test-instance"); + metadata.put("source", source); + metadata.put("timestamp", Instant.now().toString()); + metadata.put("traceId", "test-trace-id"); + + Map payload; + switch (shape) { + case "null-without-metadata": + payload = new HashMap<>(); + payload.put("context", null); + break; + case "null-with-metadata": + payload = new HashMap<>(); + payload.put("context", null); + payload.put("metadata", metadata); + break; + case "context-with-null-metadata": + payload = new HashMap<>(); + payload.put("context", context); + payload.put("metadata", null); + break; + case "context-without-metadata": + payload = new HashMap<>(); + payload.put("context", context); + break; + case "missing-context": + payload = new HashMap<>(); + payload.put("metadata", metadata); + break; + default: + throw new IllegalArgumentException("Unknown getCurrentContext response shape: " + shape); + } + + final Map responsePayload = payload; + world.getMessaging().prependAutomaticResponse(new org.finos.fdc3.proxy.support.responses.AutomaticResponse() { + @Override + public boolean filter(String messageType) { + return "getCurrentContextRequest".equals(messageType); + } + + @Override + public java.util.concurrent.CompletionStage action( + Map message, + org.finos.fdc3.proxy.support.TestMessaging messaging) { + @SuppressWarnings("unchecked") + Map meta = (Map) message.get("meta"); + Map response = new HashMap<>(); + response.put("type", "getCurrentContextResponse"); + response.put("meta", org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta(meta)); + response.put("payload", responsePayload); + org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive(messaging, response); + return java.util.concurrent.CompletableFuture.completedFuture(null); + } + }); + } + + @Given("{string} is a BroadcastEvent message on channel {string} with context {string}") + public void isABroadcastEventMessage(String field, String channel, String contextType) { + ContextMetadata metadata = defaultBroadcastMetadata(); + metadata.setSignature(new DetachedSignature()); + + Map message = new HashMap<>(); + message.put("type", "broadcastEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + Map payload = new HashMap<>(); + payload.put("channelId", handleResolve(channel, world)); + payload.put("context", ContextMap.get(contextType)); + payload.put("metadata", metadata); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a BroadcastEvent message on channel {string} with context {string} and metadata") + public void isABroadcastEventMessageWithMetadata(String field, String channel, String contextType) { + Map metadata = new HashMap<>(); + metadata.put("timestamp", Instant.now().toString()); + metadata.put("source", world.getMessaging().getAppIdentifier()); + metadata.put("traceId", world.getMessaging().createUUID()); + Map signature = new HashMap<>(); + signature.put("protected", "test-sig (protected part)"); + signature.put("signature", "test-sig (signature part)"); + metadata.put("signature", signature); + metadata.put("custom", Map.of("region", "EMEA")); + + Map message = new HashMap<>(); + message.put("type", "broadcastEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + Map payload = new HashMap<>(); + payload.put("channelId", handleResolve(channel, world)); + payload.put("context", ContextMap.get(contextType)); + payload.put("metadata", metadata); + message.put("payload", payload); + + world.set(field, message); + } + + private ContextMetadata defaultBroadcastMetadata() { + ContextMetadata metadata = ContextMetadata.appProvidable(); + metadata.setTimestamp(Instant.now()); + metadata.setSource(world.getMessaging().getAppIdentifier()); + metadata.setTraceId(world.getMessaging().createUUID()); + return metadata; + } + + @Given("{string} is a {string} message on channel {string}") + public void isAMessageOnChannel(String field, String type, String channel) { + Map message = new HashMap<>(); + message.put("type", type); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("privateChannelId", handleResolve(channel, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a {string} message on channel {string} with listenerType as {string}") + public void isAMessageOnChannelWithListenerType(String field, String type, String channel, String listenerType) { + Map message = new HashMap<>(); + message.put("type", type); + message.put("meta", world.getMessaging().createMeta()); + + Map payload = new HashMap<>(); + payload.put("channelId", handleResolve(channel, world)); + payload.put("listenerType", listenerType); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a ContextClearedEvent message on channel {string} with contextType as {string}") + public void isAContextClearedEventMessage(String field, String channel, String contextType) { + Map message = new HashMap<>(); + message.put("type", "contextClearedEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("channelId", handleResolve(channel, world)); + payload.put("contextType", handleResolve(contextType, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a channelChangedEvent message on channel {string}") + public void isAChannelChangedEventMessage(String field, String channel) { + Map message = new HashMap<>(); + message.put("type", "channelChangedEvent"); + + Map meta = new HashMap<>(); + meta.put("eventUuid", world.getMessaging().createUUID()); + meta.put("timestamp", java.time.Instant.now().toString()); + message.put("meta", meta); + + Map payload = new HashMap<>(); + payload.put("newChannelId", handleResolve(channel, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a channelChangedEvent message with currentChannelId {string}") + public void isAChannelChangedEventMessageWithCurrentChannelId(String field, String channelId) { + Map message = new HashMap<>(); + message.put("type", "channelChangedEvent"); + + Map meta = new HashMap<>(); + meta.put("eventUuid", world.getMessaging().createUUID()); + meta.put("timestamp", java.time.Instant.now().toString()); + message.put("meta", meta); + + Map payload = new HashMap<>(); + payload.put("currentChannelId", handleResolve(channelId, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a channelChangedEvent message with currentChannelId {string} and newChannelId {string}") + public void isAChannelChangedEventMessageWithCurrentAndNewChannelId( + String field, String currentChannelId, String newChannelId) { + Map message = new HashMap<>(); + message.put("type", "channelChangedEvent"); + + Map meta = new HashMap<>(); + meta.put("eventUuid", world.getMessaging().createUUID()); + meta.put("timestamp", java.time.Instant.now().toString()); + message.put("meta", meta); + + Map payload = new HashMap<>(); + payload.put("currentChannelId", handleResolve(currentChannelId, world)); + payload.put("newChannelId", handleResolve(newChannelId, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a PrivateChannelOnUnsubscribeEvent message on channel {string} with contextType as {string}") + public void isAPrivateChannelOnUnsubscribeEvent(String field, String channel, String contextType) { + Map message = new HashMap<>(); + message.put("type", "privateChannelOnUnsubscribeEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("privateChannelId", handleResolve(channel, world)); + payload.put("contextType", contextType); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a PrivateChannelOnAddContextListenerEvent message on channel {string} with contextType as {string}") + public void isAPrivateChannelOnAddContextListenerEvent(String field, String channel, String contextType) { + Map message = new HashMap<>(); + message.put("type", "privateChannelOnAddContextListenerEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("privateChannelId", handleResolve(channel, world)); + payload.put("contextType", contextType); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} is a PrivateChannelOnDisconnectEvent message on channel {string}") + public void isAPrivateChannelOnDisconnectEvent(String field, String channel) { + Map message = new HashMap<>(); + message.put("type", "privateChannelOnDisconnectEvent"); + message.put("meta", world.getMessaging().createEventMeta()); + + Map payload = new HashMap<>(); + payload.put("privateChannelId", handleResolve(channel, world)); + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} pipes types to {string}") + public void pipesTypesTo(String typeHandlerName, String field) { + List types = new ArrayList<>(); + world.set(field, types); + + class MyHandler implements ContextHandler, EventHandler { + + @Override + public void handleContext(Context context, ContextMetadata metadata) { + types.add(context.getType()); + + } + + @Override + public void handleEvent(FDC3Event event) { + @SuppressWarnings("unchecked") + Map details = (Map) event.getDetails(); + types.add((String) details.get("contextType")); + } + }; + + MyHandler ch = new MyHandler(); + + world.set(typeHandlerName, ch); + } + + @Given("{string} pipes events to {string}") + public void pipesEventsTo(String typeHandlerName, String field) { + List events = new ArrayList<>(); + world.set(field, events); + + EventHandler eh = new EventHandler() { + + @Override + public void handleEvent(FDC3Event event) { + events.add(event.getDetails()); + } + }; + + world.set(typeHandlerName, eh); + } + + @Given("{string} pipes context to {string}") + public void pipesContextTo(String contextHandlerName, String field) { + List contexts = new ArrayList<>(); + world.set(field, contexts); + + class DualHandler implements ContextHandler, EventHandler { + @Override + public void handleContext(Context context, ContextMetadata metadata) { + contexts.add(context); + } + + @Override + public void handleEvent(FDC3Event event) { + // unused for context-pipe scenarios; present so addEventListener reflection matches + } + } + + world.set(contextHandlerName, new DualHandler()); + } + + @Given("{string} pipes context and metadata to {string} and {string}") + public void pipesContextAndMetadataTo(String contextHandlerName, String contextsField, String metadatasField) { + List contexts = new ArrayList<>(); + List metadatas = new ArrayList<>(); + world.set(contextsField, contexts); + world.set(metadatasField, metadatas); + + ContextHandler ch = new ContextHandler() { + @Override + public void handleContext(Context context, ContextMetadata metadata) { + contexts.add(context); + metadatas.add(metadata); + } + }; + + world.set(contextHandlerName, ch); + } + + @When("messaging receives {string}") + public void messagingReceives(String field) { + @SuppressWarnings("unchecked") + Map message = (Map) handleResolve(field, world); + world.getMessaging().receive(message, Logger::debug); + } + + @Then("messaging will have posts") + public void messagingWillHavePosts(DataTable dt) { + int matching = dt.height() - 1; // exclude header + List> toUse = world.getMessaging().getAllPosts(); + if (toUse.size() > matching) { + toUse = toUse.subList(toUse.size() - matching, toUse.size()); + } + matchData(world, toUse, dt); + } + + @Given("channel {string} has context {string}") + public void channelHasContext(String channel, String context) { + Context ctxObject = (Context) handleResolve(context, world); + @SuppressWarnings("unchecked") + Map> state = (Map>) world.get(CHANNEL_STATE); + if (state == null) { + state = new HashMap<>(); + world.set(CHANNEL_STATE, state); + } + + List cs = state.computeIfAbsent(channel, k -> new ArrayList<>()); + cs.add(ctxObject); + } + + @Given("User Channels one, two and three") + public void userChannelsOneTwoAndThree() { + Map> state = new HashMap<>(); + state.put("one", new ArrayList<>()); + state.put("two", new ArrayList<>()); + state.put("three", new ArrayList<>()); + world.set(CHANNEL_STATE, state); + } + + @When("I destructure methods {string}, {string} from {string}") + public void iDestructureMethods(String method1, String method2, String objectField) { + Object object = handleResolve(objectField, world); + world.set("destructured_" + method1, extractDestructuredMethod(object, method1)); + world.set("destructured_" + method2, extractDestructuredMethod(object, method2)); + } + + @When("I destructure method {string} from {string}") + public void iDestructureMethod(String methodName, String objectField) { + Object object = handleResolve(objectField, world); + world.set("destructured_" + methodName, extractDestructuredMethod(object, methodName)); + } + + private static DestructuredMethod extractDestructuredMethod(Object object, String methodName) { + return new DestructuredMethod(object, methodName); + } + + @When("I call destructured {string}") + public void iCallDestructured(String methodName) { + invokeDestructured(methodName); + } + + @When("I call destructured {string} using argument {string}") + public void iCallDestructuredUsingArgument(String methodName, String param) { + invokeDestructured(methodName, handleResolve(param, world)); + } + + @When("I call destructured {string} using arguments {string} and {string}") + public void iCallDestructuredUsingTwoArguments(String methodName, String param1, String param2) { + invokeDestructured(methodName, handleResolve(param1, world), handleResolve(param2, world)); + } + + @When("I call destructured {string} using arguments {string}, {string}, and {string}") + public void iCallDestructuredUsingCommaSeparatedThreeArguments( + String methodName, String param1, String param2, String param3) { + invokeDestructured( + methodName, + handleResolve(param1, world), + handleResolve(param2, world), + handleResolve(param3, world)); + } + + @When("I call destructured {string} using arguments {string} and {string} and {string}") + public void iCallDestructuredUsingThreeArguments(String methodName, String param1, String param2, String param3) { + invokeDestructured( + methodName, + handleResolve(param1, world), + handleResolve(param2, world), + handleResolve(param3, world)); + } + + private void invokeDestructured(String methodName, Object... args) { + DestructuredMethod dm = (DestructuredMethod) world.get("destructured_" + methodName); + if (dm == null) { + // A harness problem, not a result: fail the scenario instead of storing it as though + // the API under test had rejected. + throw new IllegalStateException("No destructured method: " + methodName); + } + + try { + world.set("result", dm.invoke(args)); + } catch (NoSuchMethodException e) { + throw new IllegalStateException( + "Step refers to a method that does not exist: " + methodName, e); + } catch (InvocationTargetException e) { + world.set("result", e.getCause() != null ? e.getCause() : e); + } catch (ExecutionException e) { + world.set("result", e.getCause() != null ? e.getCause() : e); + } catch (IllegalAccessException | IllegalArgumentException e) { + throw new IllegalStateException("Step could not invoke " + methodName, e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Interrupted while invoking " + methodName, e); + } catch (Exception e) { + // Anything the invoked method threw directly. + world.set("result", e); + } + } + + /** + * Helper class to hold a destructured method reference. + */ + public static class DestructuredMethod { + private final Object target; + private final String methodName; + + public DestructuredMethod(Object target, String methodName) { + this.target = target; + this.methodName = methodName; + } + + public Object invoke(Object... args) throws Exception { + java.lang.reflect.Method method = org.finos.cucumbertestingsteps.steps.GenericSteps.findMethod(target.getClass(), methodName, args); + if (method == null) { + throw new NoSuchMethodException("Method not found: " + methodName); + } + + method.setAccessible(true); + Object result = method.invoke(target, args); + + // Handle CompletionStage/CompletableFuture + if (result instanceof java.util.concurrent.CompletionStage) { + result = ((java.util.concurrent.CompletionStage) result).toCompletableFuture().get(); + } + if (result instanceof java.util.Optional) { + return ((java.util.Optional) result).orElse(null); + } + return result; + } + + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/IntentSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/IntentSteps.java new file mode 100644 index 00000000..087c851c --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/IntentSteps.java @@ -0,0 +1,418 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.metadata.DetachedSignature; +import org.finos.fdc3.proxy.support.ParseAntiReplayClaims; +import org.finos.fdc3.api.metadata.DisplayMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.proxy.channels.DefaultChannel; +import org.finos.fdc3.proxy.channels.DefaultPrivateChannel; +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.world.CustomWorld; +import org.finos.fdc3.api.channel.Channel; + +import io.cucumber.java.en.Given; + +import static org.finos.cucumbertestingsteps.support.MatchingUtils.handleResolve; + +/** + * Cucumber step definitions for intent-related tests. + */ +public class IntentSteps { + + private final CustomWorld world; + + public IntentSteps(CustomWorld world) { + this.world = world; + } + + @Given("app {string}") + public void app(String appStr) { + String[] parts = appStr.split("/"); + String appId = parts[0]; + String instanceId = parts.length > 1 ? parts[1] : null; + + AppIdentifier app = createAppIdentifier(appId, instanceId); + world.getMessaging().addAppIntentDetail(createIntentDetail(app, null, null, null)); + if (instanceId != null) { + world.set(instanceId, app); + } + } + + @Given("{string} is app identifier {string}") + public void isAppIdentifier(String field, String appId) { + world.set(field, new AppIdentifier(appId)); + } + + @Given("{string} is an array of contexts including {string} and {string}") + public void isArrayOfContextsIncluding(String field, String valueOne, String valueTwo) { + world.set(field, List.of(valueOne, valueTwo)); + } + + @Given("app {string} resolves intent {string}") + public void appResolvesIntent(String appStr, String intent) { + String[] parts = appStr.split("/"); + String appId = parts[0]; + String instanceId = parts.length > 1 ? parts[1] : null; + + AppIdentifier app = createAppIdentifier(appId, instanceId); + world.getMessaging().addAppIntentDetail(createIntentDetail(app, intent, null, null)); + if (instanceId != null) { + world.set(instanceId, app); + } + world.set(appId, createAppIdentifier(appId, null)); + } + + @Given("app {string} resolves intent {string} with result type {string}") + public void appResolvesIntentWithResultType(String appStr, String intent, String resultType) { + String[] parts = appStr.split("/"); + String appId = parts[0]; + String instanceId = parts.length > 1 ? parts[1] : null; + + AppIdentifier app = createAppIdentifier(appId, instanceId); + world.getMessaging().addAppIntentDetail(createIntentDetail(app, intent, null, resultType)); + if (instanceId != null) { + world.set(instanceId, app); + } + world.set(appId, createAppIdentifier(appId, null)); + } + + @Given("app {string} resolves intent {string} with context {string}") + public void appResolvesIntentWithContext(String appStr, String intent, String context) { + String[] parts = appStr.split("/"); + String appId = parts[0]; + String instanceId = parts.length > 1 ? parts[1] : null; + + AppIdentifier app = createAppIdentifier(appId, instanceId); + world.getMessaging().addAppIntentDetail(createIntentDetail(app, intent, context, null)); + if (instanceId != null) { + world.set(instanceId, app); + } + world.set(appId, createAppIdentifier(appId, null)); + } + + @Given("app {string} resolves intent {string} with context {string} and result type {string}") + public void appResolvesIntentWithContextAndResultType(String appStr, String intent, String context, String resultType) { + String[] parts = appStr.split("/"); + String appId = parts[0]; + String instanceId = parts.length > 1 ? parts[1] : null; + + AppIdentifier app = createAppIdentifier(appId, instanceId); + world.getMessaging().addAppIntentDetail(createIntentDetail(app, intent, context, resultType)); + if (instanceId != null) { + world.set(instanceId, app); + } + } + + @Given("Raise Intent returns a context of {string}") + public void raiseIntentReturnsContext(String result) { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setContext((Context) handleResolve(result, world)); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("Raise Intent returns a context of {string} with traceId {string} and signature {string}") + public void raiseIntentReturnsContextWithMetadata(String result, String traceId, String signature) { + raiseIntentReturnsContextWithMetadataAndAntiReplay(result, traceId, signature, null); + } + + @Given("Raise Intent returns a context of {string} with traceId {string} and signature {string} and antiReplay claims {string}") + public void raiseIntentReturnsContextWithMetadataAndAntiReplay( + String result, String traceId, String signature, String antiReplayClaims) { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setContext((Context) handleResolve(result, world)); + intentResult.setResultMetadata(metadataWithTraceSignatureAndAntiReplay(traceId, signature, antiReplayClaims)); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("{string} is metadata with traceId {string} and signature {string}") + public void isMetadataWithTraceId(String field, String traceId, String signature) { + world.set(field, metadataWithTraceSignatureAndAntiReplay(traceId, signature, null)); + } + + @Given("{string} is metadata with traceId {string} and signature {string} and antiReplay claims {string}") + public void isMetadataWithTraceIdAndAntiReplay(String field, String traceId, String signature, String antiReplayClaims) { + world.set(field, metadataWithTraceSignatureAndAntiReplay(traceId, signature, antiReplayClaims)); + } + + private ContextMetadata metadataWithTraceSignatureAndAntiReplay( + String traceId, String signature, String antiReplayClaims) { + ContextMetadata metadata = ContextMetadata.appProvidable(); + metadata.setTraceId(traceId); + metadata.setSignature(testDetachedSignature(signature)); + if (antiReplayClaims != null) { + metadata.setAntiReplay(ParseAntiReplayClaims.parse(antiReplayClaims)); + } + Map custom = new HashMap<>(); + custom.put("priority", "high"); + metadata.setCustom(custom); + return metadata; + } + + @Given("Raise Intent will throw a {string} error") + public void raiseIntentWillThrowError(String error) { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setError(error); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("Raise Intent returns no result") + public void raiseIntentReturnsNoResult() { + world.getMessaging().setIntentResult(new TestMessaging.PossibleIntentResult()); + } + + @Given("Raise Intent times out") + public void raiseIntentTimesOut() { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setTimeout(true); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("Raise Intent returns an app channel") + public void raiseIntentReturnsAppChannel() { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setChannel(new DefaultChannel( + world.getMessaging(), + world.getMessaging().getTimeoutMs(), + "result-channel", + org.finos.fdc3.api.channel.Channel.Type.App, + null + )); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("Raise Intent returns a user channel") + public void raiseIntentReturnsUserChannel() { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setChannel(new DefaultChannel( + world.getMessaging(), + world.getMessaging().getTimeoutMs(), + "result-channel", + org.finos.fdc3.api.channel.Channel.Type.User, + null + )); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("Raise Intent returns a private channel") + public void raiseIntentReturnsPrivateChannel() { + TestMessaging.PossibleIntentResult intentResult = new TestMessaging.PossibleIntentResult(); + intentResult.setChannel(new DefaultPrivateChannel( + world.getMessaging(), + world.getMessaging().getTimeoutMs(), + "result-channel" + )); + world.getMessaging().setIntentResult(intentResult); + } + + @Given("{string} is a intentEvent message with intent {string} and context {string}") + public void isAIntentEventMessage(String field, String intent, String context) { + Map message = new HashMap<>(); + message.put("type", "intentEvent"); + + Map meta = new HashMap<>(); + meta.put("eventUuid", world.getMessaging().createUUID()); + meta.put("timestamp", Instant.now().toString()); + message.put("meta", meta); + + Map payload = new HashMap<>(); + Map originatingApp = new HashMap<>(); + originatingApp.put("appId", "some-app-id"); + originatingApp.put("desktopAgent", "some-desktop-agent"); + payload.put("originatingApp", originatingApp); + payload.put("context", handleResolve(context, world)); + payload.put("intent", intent); + payload.put("raiseIntentRequestUuid", "request-id"); + + ContextMetadata metadata = ContextMetadata.appProvidable(); + metadata.setTimestamp(Instant.now()); + metadata.setSource(world.getMessaging().getAppIdentifier()); + metadata.setTraceId(world.getMessaging().createUUID()); + payload.put("metadata", metadata); + + message.put("payload", payload); + + world.set(field, message); + } + + @Given("{string} pipes intent to {string}") + public void pipesIntentTo(String intentHandlerName, String field) { + List> intents = new ArrayList<>(); + world.set(field, intents); + + IntentHandler ih = new IntentHandler() { + + @Override + public CompletionStage> handleIntent(Context context, ContextMetadata contextMetadata) { + Map item = new HashMap<>(); + item.put("context", context); + item.put("metadata", contextMetadata); + intents.add(item); + return CompletableFuture.completedFuture(Optional.empty()); + } + }; + + world.set(intentHandlerName, ih); + } + + @Given("{string} returns a context item") + public void returnsAContextItem(String intentHandlerName) { + IntentHandler ih = new IntentHandler() { + + @Override + public CompletionStage> handleIntent(Context context, ContextMetadata contextMetadata) { + Map id = new HashMap<>(); + id.put("in", "one"); + id.put("out", "two"); + return CompletableFuture.completedFuture(Optional.of(new Context("fdc3.returned-intent", null, id))); + } + }; + + world.set(intentHandlerName, ih); + } + + @Given("{string} returns a channel") + public void returnsAChannel(String intentHandlerName) { + IntentHandler ih = new IntentHandler() { + + @Override + public CompletionStage> handleIntent(Context context, + ContextMetadata contextMetadata) { + DisplayMetadata dm = new DisplayMetadata("Some Channel", "ochre","b;"); + Channel c = new Channel() { + + @Override + public String getId() { + return "some-channel-id"; + } + + @Override + public Type getType() { + return Type.Private; + } + + @Override + public DisplayMetadata getDisplayMetadata() { + return dm; + } + + @Override + public CompletionStage broadcast(Context context) { + return null; + } + + @Override + public CompletionStage> getCurrentContext() { + return null; + } + + @Override + public CompletionStage> getCurrentContext(String contextType) { + return null; + } + + @Override + public CompletionStage clearContext(String contextType) { + return null; + } + + @Override + public CompletionStage addContextListener(String contextType, ContextHandler handler) { + return null; + } + + @Override + public CompletionStage addContextListener(java.util.List contextTypes, ContextHandler handler) { + return null; + } + + @Override + public CompletionStage addEventListener(String type, EventHandler handler) { + return null; + } + + @Override + public CompletionStage> getCurrentContextWithMetadata( + String contextType) { + return null; + } + + @Override + public CompletionStage broadcast(Context context, AppProvidableContextMetadata metadata) { + return null; + } + + }; + return CompletableFuture.completedFuture(Optional.of(c)); + } + + }; + world.set(intentHandlerName, ih); + } + + @Given("{string} returns a void promise") + public void returnsAVoidPromise(String intentHandlerName) { + IntentHandler ih = new IntentHandler() { + + @Override + public CompletionStage> handleIntent(Context context, ContextMetadata contextMetadata) { + return CompletableFuture.completedFuture(Optional.ofNullable(null)); + } + }; + world.set(intentHandlerName, ih); + } + + private AppIdentifier createAppIdentifier(String appId, String instanceId) { + return new AppIdentifier(appId, instanceId, "some-desktop-agent"); + } + + private TestMessaging.IntentDetail createIntentDetail(AppIdentifier app, String intent, String context, String resultType) { + TestMessaging.IntentDetail detail = new TestMessaging.IntentDetail(); + detail.setApp(app); + detail.setIntent(intent); + detail.setContext(context); + detail.setResultType(resultType); + return detail; + } + + private static DetachedSignature testDetachedSignature(String base) { + DetachedSignature sig = new DetachedSignature(); + sig.setSignature(base + " (signature part)"); + sig.setProtectedHeader(base + " (protected part)"); + return sig; + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/SchemaSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/SchemaSteps.java new file mode 100644 index 00000000..bebb2547 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/SchemaSteps.java @@ -0,0 +1,48 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import java.io.IOException; + +import org.finos.fdc3.proxy.schema.Fdc3SchemaMatchers; +import org.finos.fdc3.proxy.schema.LoadSchemas; + +import io.cucumber.java.en.Given; +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * Cucumber glue for FDC3 schema loading and matchers. + * Equivalent to {@code setupSchemaSteps()} and {@code registerFdc3SchemaMatchers()} in + * {@code @finos/fdc3-schema/test}. + */ +public class SchemaSteps { + + static { + Fdc3SchemaMatchers.registerFdc3SchemaMatchers(); + } + + private final PropsWorld world; + + public SchemaSteps(PropsWorld world) { + this.world = world; + } + + @Given("schemas loaded") + public void schemasLoaded() throws IOException { + LoadSchemas.loadSchemasIntoWorld(world); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/UtilSteps.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/UtilSteps.java new file mode 100644 index 00000000..f5b1ce79 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/steps/UtilSteps.java @@ -0,0 +1,127 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.steps; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.errors.OpenError; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.util.ThrowIfUndefined; +import org.finos.fdc3.proxy.world.CustomWorld; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; + +/** + * Cucumber step definitions for utility tests. + */ +public class UtilSteps { + + private final CustomWorld world; + + public UtilSteps(CustomWorld world) { + this.world = world; + } + + @Given("close will fail") + public void closeWillFail() { + if (world.hasMessaging()) { + world.getMessaging().setCloseShouldFail(true); + } + } + + /** + * A schema-valid response whose payload is empty, which is the shape + * {@code throwIfUndefined} exists to catch. + */ + private static Map dummyResponse() { + Map meta = new HashMap<>(); + meta.put("requestUuid", "123"); + meta.put("responseUuid", "456"); + meta.put("timestamp", Instant.now().toString()); + + Map message = new HashMap<>(); + message.put("type", "broadcastResponse"); + message.put("meta", meta); + message.put("payload", new HashMap()); + return message; + } + + @When("I call throwIfUndefined it throws if a specified property is not defined") + public void throwIfUndefinedThrows() { + Map someObject = new HashMap<>(); + someObject.put("someProperty", "value"); + + Exception thrown = null; + try { + ThrowIfUndefined.throwIfUndefined( + someObject.get("nonExistent"), + "Deliberately undefined prop did not exist ;-)", + dummyResponse(), + OpenError.MalformedContext.toString()); + } catch (Exception e) { + thrown = e; + } + + assertNotNull(thrown, "throwIfUndefined should throw for an absent property"); + // The message has to be the bare FDC3 error name, since that is what applications match on. + assertEquals(OpenError.MalformedContext.toString(), thrown.getMessage()); + } + + @When("I call throwIfUndefined it does NOT throw if a specified property IS defined") + public void throwIfUndefinedDoesNotThrow() { + Map someObject = new HashMap<>(); + someObject.put("someProperty", "value"); + + Exception thrown = null; + try { + ThrowIfUndefined.throwIfUndefined( + someObject.get("someProperty"), + "Deliberately undefined prop did not exist ;-)", + dummyResponse(), + OpenError.MalformedContext.toString()); + } catch (Exception e) { + thrown = e; + } + + assertNull(thrown, "throwIfUndefined should not throw for a property that is present"); + } + + @When("All log functions are used with a message") + public void allLogFunctionsWithMessage() { + Logger.debug("Debug msg"); + Logger.info("Log msg"); + Logger.warn("Warning msg"); + Logger.error("Error msg"); + } + + @When("All log functions are used with an error") + public void allLogFunctionsWithError() { + String testError = "Test error - This is expected on the console"; + Logger.debug("debug-level error: ", new Exception(testError)); + Logger.info("log-level error: ", new Exception(testError)); + Logger.warn("warn-level error: ", new Exception(testError)); + Logger.error("error-level error: ", new Exception(testError)); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ContextMap.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ContextMap.java new file mode 100644 index 00000000..74a6e0f0 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ContextMap.java @@ -0,0 +1,84 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.support; + +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.context.Context; + +/** + * Pre-defined context objects for testing. + */ +public final class ContextMap { + + private static final Map CONTEXTS = new HashMap<>(); + + static { + // fdc3.instrument + Map instrumentId = new HashMap<>(); + instrumentId.put("ticker", "AAPL"); + Context instrument = new Context("fdc3.instrument", "Apple", instrumentId); + CONTEXTS.put("fdc3.instrument", instrument); + + // fdc3.country + Map countryId = new HashMap<>(); + countryId.put("COUNTRY_ISOALPHA2", "SE"); + countryId.put("COUNTRY_ISOALPHA3", "SWE"); + Context country = new Context("fdc3.country", "Sweden", countryId); + CONTEXTS.put("fdc3.country", country); + + // fdc3.unsupported + Context unsupported = new Context("fdc3.unsupported"); + unsupported.put("bogus", true); + CONTEXTS.put("fdc3.unsupported", unsupported); + + // fdc3.cancel-me + Context cancelMe = new Context("fdc3.cancel-me"); + CONTEXTS.put("fdc3.cancel-me", cancelMe); + } + + private ContextMap() { + // Utility class + } + + /** + * Returns a fresh copy of the named context. + *

+ * {@link Context} extends {@code HashMap}, so handing out the stored instance let one + * scenario's mutations leak into every later scenario that asked for the same type, making + * results depend on execution order. + * + * @param type the context type, e.g. {@code fdc3.instrument} + * @return a copy that the caller may modify freely, or null if the type is unknown + */ + public static Context get(String type) { + Context template = CONTEXTS.get(type); + if (template == null) { + return null; + } + + Context copy = new Context(); + copy.putAll(template); + return copy; + } + + public static boolean contains(String type) { + return CONTEXTS.containsKey(type); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ParseAntiReplayClaims.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ParseAntiReplayClaims.java new file mode 100644 index 00000000..f7817f8d --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/ParseAntiReplayClaims.java @@ -0,0 +1,36 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.support; + +import org.finos.fdc3.api.metadata.AntiReplayClaims; + +public final class ParseAntiReplayClaims { + + private ParseAntiReplayClaims() { + } + + public static AntiReplayClaims parse(String claims) { + String[] parts = claims.split("/"); + if (parts.length != 3) { + throw new IllegalArgumentException( + "antiReplay claims must be three slash-separated parts (iat/exp/jti), got: " + claims); + } + long iat = Long.parseLong(parts[0]); + long exp = Long.parseLong(parts[1]); + return new AntiReplayClaims(iat, exp, parts[2]); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleChannelSelector.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleChannelSelector.java new file mode 100644 index 00000000..e13cd7a7 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleChannelSelector.java @@ -0,0 +1,111 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.support; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.ui.ChannelSelector; + +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * A simple channel selector for testing purposes. + *

+ * This selector stores channel state in the PropsWorld for verification. + *

+ * This is equivalent to the TypeScript SimpleChannelSelector class. + */ +public class SimpleChannelSelector implements ChannelSelector { + + public static final String CHANNEL_STATE = "CHANNEL_STATE"; + + private final PropsWorld world; + private Consumer channelChangeCallback; + private String channelId; + private List channels = new ArrayList<>(); + + public SimpleChannelSelector(PropsWorld world) { + this.world = world; + } + + @Override + public void updateChannel(String channelId, List availableChannels) { + this.channelId = channelId; + this.channels = new ArrayList<>(availableChannels); + world.set("channelId", channelId); + world.set("channels", availableChannels); + } + + @Override + public void setChannelChangeCallback(Consumer callback) { + this.channelChangeCallback = callback; + } + + /** + * Simulate a channel change (for testing). + * + * @param channelId the new channel ID, or null to leave channel + */ + public void selectChannel(String channelId) { + this.channelId = channelId; + if (channelChangeCallback != null) { + channelChangeCallback.accept(channelId); + } else { + throw new IllegalStateException("Channel selected before Channel Change callback was set!"); + } + } + + public void selectFirstChannel() { + if (!channels.isEmpty()) { + selectChannel(channels.get(0).getId()); + } + } + + public void selectSecondChannel() { + if (channels.size() > 1) { + selectChannel(channels.get(1).getId()); + } + } + + public void deselectChannel() { + selectChannel(null); + } + + public String getChannelId() { + return channelId; + } + + public List getChannels() { + return channels; + } + + @Override + public CompletionStage connect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage disconnect() { + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleIntentResolver.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleIntentResolver.java new file mode 100644 index 00000000..bd4347f3 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/SimpleIntentResolver.java @@ -0,0 +1,92 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.support; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.IntentMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.ui.IntentResolutionChoice; +import org.finos.fdc3.api.ui.IntentResolver; +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * A simple intent resolver for testing purposes. + *

+ * This resolver automatically selects the first intent/app in the list, + * unless the context type is "fdc3.cancel-me", in which case it returns null (cancelled). + *

+ * This is equivalent to the TypeScript SimpleIntentResolver class. + */ +public class SimpleIntentResolver implements IntentResolver { + + private final PropsWorld world; + + public SimpleIntentResolver(PropsWorld world) { + this.world = world; + } + + @Override + public CompletionStage chooseIntent(List appIntents, Context context) { + // Cancel if the context type is "fdc3.cancel-me" + if ("fdc3.cancel-me".equals(context.getType())) { + return CompletableFuture.completedFuture(null); + } + + // Select the first intent and first app + AppIntent firstIntent = appIntents.get(0); + IntentMetadata intent = firstIntent.getIntent(); + // getApps() returns AppMetadata[] so convert to list + List apps = Arrays.asList(firstIntent.getApps()); + AppMetadata firstApp = apps.get(0); + + // Create an AppIdentifier from the AppMetadata + AppIdentifier appIdentifier = new AppIdentifier( + firstApp.getAppId(), + firstApp.getInstanceId(), + firstApp.getDesktopAgent() + ); + + // Create the resolution choice + IntentResolutionChoice resolution = new IntentResolutionChoice( + intent.getName(), + appIdentifier + ); + + // Store for testing verification + world.set("intent-resolution", resolution); + + return CompletableFuture.completedFuture(resolution); + } + + @Override + public CompletionStage connect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage disconnect() { + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/TestMessaging.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/TestMessaging.java new file mode 100644 index 00000000..8f2695b7 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/TestMessaging.java @@ -0,0 +1,347 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.support; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.listeners.RegisterableListener; +import org.finos.fdc3.proxy.messaging.AbstractMessaging; +import org.finos.fdc3.proxy.support.responses.AddEventListenerResponse; +import org.finos.fdc3.proxy.support.responses.AutomaticResponse; +import org.finos.fdc3.proxy.support.responses.ChannelStateResponse; +import org.finos.fdc3.proxy.support.responses.CloseResponse; +import org.finos.fdc3.proxy.support.responses.CreatePrivateChannelResponse; +import org.finos.fdc3.proxy.support.responses.DisconnectPrivateChannelResponse; +import org.finos.fdc3.proxy.support.responses.FindInstancesResponse; +import org.finos.fdc3.proxy.support.responses.FindIntentByContextResponse; +import org.finos.fdc3.proxy.support.responses.FindIntentResponse; +import org.finos.fdc3.proxy.support.responses.GetAppMetadataResponse; +import org.finos.fdc3.proxy.support.responses.GetInfoResponse; +import org.finos.fdc3.proxy.support.responses.GetOrCreateChannelResponse; +import org.finos.fdc3.proxy.support.responses.GetUserChannelsResponse; +import org.finos.fdc3.proxy.support.responses.IntentResultResponse; +import org.finos.fdc3.proxy.support.responses.OpenResponse; +import org.finos.fdc3.proxy.support.responses.RaiseIntentForContextResponse; +import org.finos.fdc3.proxy.support.responses.RaiseIntentResponse; +import org.finos.fdc3.proxy.support.responses.RegisterListenersResponse; +import org.finos.fdc3.proxy.support.responses.UnsubscribeListenersResponse; + +/** + * Test implementation of messaging for Cucumber tests. + * Simulates the message exchange between the Desktop Agent and apps. + */ +public class TestMessaging extends AbstractMessaging { + + private final List> allPosts = new ArrayList<>(); + private final Map listeners = new ConcurrentHashMap<>(); + private final List intentDetails = new ArrayList<>(); + private final Map> channelState; + private final List automaticResponses; + + private Channel currentChannel; + private PossibleIntentResult intentResult; + private boolean closeShouldFail; + + public TestMessaging(Map> channelState) { + this(channelState, null); + } + + public TestMessaging(Map> channelState, String initialChannelId) { + super(new AppIdentifier("cucumber-app", "cucumber-instance", "testing-da")); + this.channelState = channelState != null ? channelState : new HashMap<>(); + + // Set up automatic responses for various message types + this.automaticResponses = new ArrayList<>(); + this.automaticResponses.add(new FindIntentResponse()); + this.automaticResponses.add(new FindIntentByContextResponse()); + this.automaticResponses.add(new RaiseIntentResponse()); + this.automaticResponses.add(new RaiseIntentForContextResponse()); + this.automaticResponses.add(new IntentResultResponse()); + this.automaticResponses.add(new GetAppMetadataResponse()); + this.automaticResponses.add(new GetInfoResponse()); + this.automaticResponses.add(new FindInstancesResponse()); + this.automaticResponses.add(new OpenResponse()); + this.automaticResponses.add(new CloseResponse()); + this.automaticResponses.add(new GetOrCreateChannelResponse()); + this.automaticResponses.add(new ChannelStateResponse(this.channelState, initialChannelId)); + this.automaticResponses.add(new GetUserChannelsResponse()); + this.automaticResponses.add(new RegisterListenersResponse()); + this.automaticResponses.add(new UnsubscribeListenersResponse()); + this.automaticResponses.add(new CreatePrivateChannelResponse()); + this.automaticResponses.add(new DisconnectPrivateChannelResponse()); + } + + /** + * Prepends an automatic response so it is tried before the built-in handlers + * (mirrors TypeScript {@code automaticResponses.unshift}). + */ + public void prependAutomaticResponse(AutomaticResponse response) { + automaticResponses.add(0, response); + } + + @Override + public String createUUID() { + return UUID.randomUUID().toString(); + } + + public int getTimeoutMs() { + return 1000; + } + + public synchronized List> getAllPosts() { + return allPosts; + } + + @Override + public synchronized CompletionStage post(Map message) { + allPosts.add(message); + + String type = (String) message.get("type"); + if (!isGoodbye(type)) { + for (AutomaticResponse ar : automaticResponses) { + if (ar.filter(type)) { + return ar.action(message, this); + } + } + } + + return CompletableFuture.completedFuture(null); + } + + private static boolean isGoodbye(String type) { + return "WSCPGoodbye".equals(type) || "WCP6Goodbye".equals(type); + } + + @Override + public void register(RegisterableListener listener) { + if (listener.getId() == null) { + throw new IllegalArgumentException("Listener must have ID set"); + } + listeners.put(listener.getId(), listener); + } + + @Override + public void unregister(String id) { + listeners.remove(id); + } + + @Override + public CompletionStage disconnect() { + Map bye = new HashMap<>(); + bye.put("type", "WSCPGoodbye"); + Map meta = new HashMap<>(); + meta.put("timestamp", OffsetDateTime.now().toString()); + bye.put("meta", meta); + return post(bye).whenComplete((ignored, error) -> shutdownScheduler()); + } + + public void addAppIntentDetail(IntentDetail detail) { + intentDetails.add(detail); + } + + public List getIntentDetails() { + return intentDetails; + } + + /** + * Used in testing steps to create response metadata. + */ + public Map createResponseMeta() { + Map meta = new HashMap<>(); + meta.put("requestUuid", createUUID()); + meta.put("responseUuid", createUUID()); + meta.put("timestamp", Instant.now().toString()); + Map source = new HashMap<>(); + source.put("appId", getAppIdentifier().getAppId()); + if (getAppIdentifier().getInstanceId() != null) { + source.put("instanceId", getAppIdentifier().getInstanceId()); + } + meta.put("source", source); + return meta; + } + + /** + * Used in testing steps to create event metadata. + */ + public Map createEventMeta() { + Map meta = new HashMap<>(); + meta.put("requestUuid", createUUID()); + meta.put("eventUuid", createUUID()); + meta.put("timestamp", Instant.now().toString()); + Map source = new HashMap<>(); + source.put("appId", getAppIdentifier().getAppId()); + if (getAppIdentifier().getInstanceId() != null) { + source.put("instanceId", getAppIdentifier().getInstanceId()); + } + meta.put("source", source); + return meta; + } + + /** + * Simulates receiving a message from the Desktop Agent. + * Dispatches to all registered listeners that match the message. + */ + public void receive(Map message, Consumer log) { + listeners.forEach((id, listener) -> { + if (listener.filter(message)) { + if (log != null) { + log.accept("Processing in " + id); + } + listener.action(message); + } else { + if (log != null) { + log.accept("Ignoring in " + id); + } + } + }); + } + + public PossibleIntentResult getIntentResult() { + return intentResult; + } + + public void setIntentResult(PossibleIntentResult result) { + this.intentResult = result; + } + + public Channel getCurrentChannel() { + return currentChannel; + } + + public void setCurrentChannel(Channel channel) { + this.currentChannel = channel; + } + + public boolean isCloseShouldFail() { + return closeShouldFail; + } + + public void setCloseShouldFail(boolean closeShouldFail) { + this.closeShouldFail = closeShouldFail; + } + + public Map> getChannelState() { + return channelState; + } + + /** + * Represents details about an intent that can be resolved. + */ + public static class IntentDetail { + private AppIdentifier app; + private String intent; + private String context; + private String resultType; + + public AppIdentifier getApp() { + return app; + } + + public void setApp(AppIdentifier app) { + this.app = app; + } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getResultType() { + return resultType; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + } + + /** + * Represents a possible result from raising an intent. + */ + public static class PossibleIntentResult { + private Context context; + private Channel channel; + private ContextMetadata resultMetadata; + private String error; + private boolean timeout; + + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + + public Channel getChannel() { + return channel; + } + + public void setChannel(Channel channel) { + this.channel = channel; + } + + public org.finos.fdc3.api.metadata.ContextMetadata getResultMetadata() { + return resultMetadata; + } + + public void setResultMetadata(org.finos.fdc3.api.metadata.ContextMetadata resultMetadata) { + this.resultMetadata = resultMetadata; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public boolean isTimeout() { + return timeout; + } + + public void setTimeout(boolean timeout) { + this.timeout = timeout; + } + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AddEventListenerResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AddEventListenerResponse.java new file mode 100644 index 00000000..eb597695 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AddEventListenerResponse.java @@ -0,0 +1,46 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.atomic.AtomicInteger; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to addEventListener requests. + */ +public class AddEventListenerResponse implements AutomaticResponse { + + private final AtomicInteger count = new AtomicInteger(0); + + @Override + public boolean filter(String messageType) { + return "addEventListenerRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + Map payload = new HashMap<>(); + payload.put("listenerUUID", "listener-" + count.getAndIncrement()); + + Map response = new HashMap<>(); + response.put("type", "addEventListenerResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AutomaticResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AutomaticResponse.java new file mode 100644 index 00000000..e865b33c --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/AutomaticResponse.java @@ -0,0 +1,26 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import java.util.Map; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Interface for automatic responses to test messages. + */ +public interface AutomaticResponse { + + /** + * Returns true if this response should handle messages of the given type. + */ + boolean filter(String messageType); + + /** + * Processes the message and sends an appropriate response. + */ + CompletionStage action(Map message, TestMessaging messaging); +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ChannelStateResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ChannelStateResponse.java new file mode 100644 index 00000000..591fd198 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ChannelStateResponse.java @@ -0,0 +1,297 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Handles channel-related requests: broadcast, join, leave, getCurrentChannel, + * addContextListener, contextListenerUnsubscribe, getCurrentContext. + * + * Equivalent to ChannelState.ts in the TypeScript implementation. + */ +public class ChannelStateResponse implements AutomaticResponse { + + private String channelId = null; + private final Map> listeners = new HashMap<>(); + private final Map> contextHistory; + + public ChannelStateResponse(Map> contextHistory) { + this(contextHistory, null); + } + + public ChannelStateResponse(Map> contextHistory, String initialChannelId) { + this.contextHistory = contextHistory != null ? contextHistory : new HashMap<>(); + this.channelId = initialChannelId; + } + + @Override + public boolean filter(String messageType) { + return "broadcastRequest".equals(messageType) || + "clearContextRequest".equals(messageType) || + "joinUserChannelRequest".equals(messageType) || + "leaveCurrentChannelRequest".equals(messageType) || + "getCurrentChannelRequest".equals(messageType) || + "addContextListenerRequest".equals(messageType) || + "contextListenerUnsubscribeRequest".equals(messageType) || + "getCurrentContextRequest".equals(messageType); + } + + @Override + public CompletionStage action(Map message, TestMessaging messaging) { + String type = (String) message.get("type"); + Map response = null; + + switch (type) { + case "broadcastRequest": + response = createBroadcastResponse(message); + break; + case "clearContextRequest": + response = createClearContextResponse(message); + break; + case "joinUserChannelRequest": + response = createJoinResponse(message); + break; + case "leaveCurrentChannelRequest": + response = createLeaveResponse(message); + break; + case "getCurrentChannelRequest": + response = createGetChannelResponse(message); + break; + case "addContextListenerRequest": + response = createAddListenerResponse(message); + break; + case "contextListenerUnsubscribeRequest": + response = createUnsubscribeResponse(message); + break; + case "getCurrentContextRequest": + response = createGetContextResponse(message); + break; + } + + if (response != null) { + scheduleReceive(messaging, response); + } + return CompletableFuture.completedFuture(null); + } + + @SuppressWarnings("unchecked") + private Map createBroadcastResponse(Map message) { + Map meta = (Map) message.get("meta"); + Map payload = (Map) message.get("payload"); + String channel = (String) payload.get("channelId"); + Object context = payload.get("context"); + + // Store context in history + contextHistory.computeIfAbsent(channel, k -> new ArrayList<>()); + if (context instanceof Context) { + contextHistory.get(channel).add(0, (Context) context); + } else if (context instanceof Map) { + contextHistory.get(channel).add(0, Context.fromMap((Map) context)); + } + + Map response = new HashMap<>(); + response.put("type", "broadcastResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + return response; + } + + /** + * Drops the stored context so that a following {@code getCurrentContext} sees the channel as + * cleared. A null {@code contextType} clears every type, matching the standard. + */ + @SuppressWarnings("unchecked") + private Map createClearContextResponse(Map message) { + Map meta = (Map) message.get("meta"); + Map payload = (Map) message.get("payload"); + String channel = (String) payload.get("channelId"); + String contextType = (String) payload.get("contextType"); + + List contexts = contextHistory.get(channel); + if (contexts != null) { + if (contextType == null) { + contexts.clear(); + } else { + contexts.removeIf(context -> contextType.equals(context.getType())); + } + } + + Map response = new HashMap<>(); + response.put("type", "clearContextResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + return response; + } + + @SuppressWarnings("unchecked") + private Map createJoinResponse(Map message) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + String requestedChannel = (String) msgPayload.get("channelId"); + + Map responsePayload = new HashMap<>(); + + if ("nonexistent".equals(requestedChannel)) { + responsePayload.put("error", "NoChannelFound"); + } else { + this.channelId = requestedChannel; + } + + Map response = new HashMap<>(); + response.put("type", "joinUserChannelResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", responsePayload); + return response; + } + + @SuppressWarnings("unchecked") + private Map createLeaveResponse(Map message) { + Map meta = (Map) message.get("meta"); + this.channelId = null; + + Map response = new HashMap<>(); + response.put("type", "leaveCurrentChannelResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + return response; + } + + @SuppressWarnings("unchecked") + private Map createGetChannelResponse(Map message) { + Map meta = (Map) message.get("meta"); + + Map responsePayload = new HashMap<>(); + if (this.channelId != null) { + Map channel = new HashMap<>(); + channel.put("id", this.channelId); + channel.put("type", "user"); + + Map displayMetadata = new HashMap<>(); + displayMetadata.put("name", "The " + this.channelId + " channel"); + displayMetadata.put("color", "red"); + displayMetadata.put("glyph", "triangle"); + channel.put("displayMetadata", displayMetadata); + + responsePayload.put("channel", channel); + } else { + responsePayload.put("channel", null); + } + + Map response = new HashMap<>(); + response.put("type", "getCurrentChannelResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", responsePayload); + return response; + } + + @SuppressWarnings("unchecked") + private Map createAddListenerResponse(Map message) { + Map meta = (Map) message.get("meta"); + String id = UUID.randomUUID().toString(); + + if (this.channelId != null) { + listeners.computeIfAbsent(this.channelId, k -> new ArrayList<>()); + listeners.get(this.channelId).add(id); + } + + Map responsePayload = new HashMap<>(); + responsePayload.put("listenerUUID", id); + + Map response = new HashMap<>(); + response.put("type", "addContextListenerResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", responsePayload); + return response; + } + + @SuppressWarnings("unchecked") + private Map createUnsubscribeResponse(Map message) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + String listenerId = (String) msgPayload.get("listenerUUID"); + + // Remove listener from all channels + for (List channelListeners : listeners.values()) { + channelListeners.remove(listenerId); + } + + Map response = new HashMap<>(); + response.put("type", "contextListenerUnsubscribeResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + return response; + } + + @SuppressWarnings("unchecked") + private Map createGetContextResponse(Map message) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + String channel = (String) msgPayload.get("channelId"); + String contextType = (String) msgPayload.get("contextType"); + + List contexts = contextHistory.get(channel); + Context foundContext = null; + + if (contexts != null && !contexts.isEmpty()) { + if (contextType != null) { + // Find matching context type + for (Context ctx : contexts) { + if (contextType.equals(ctx.getType())) { + foundContext = ctx; + break; + } + } + } else { + // Return first (most recent) context + foundContext = contexts.get(0); + } + } + + Map responsePayload = new HashMap<>(); + responsePayload.put("context", foundContext); + if (foundContext != null) { + Map metadata = new HashMap<>(); + Map source = new HashMap<>(); + source.put("appId", "test-app"); + source.put("instanceId", "test-instance"); + metadata.put("source", source); + metadata.put("timestamp", java.time.Instant.now().toString()); + metadata.put("traceId", "test-trace-id"); + Map signature = new HashMap<>(); + signature.put("protected", "test-signature (protected part)"); + signature.put("signature", "test-signature (signature part)"); + metadata.put("signature", signature); + Map custom = new HashMap<>(); + custom.put("key", "value"); + metadata.put("custom", custom); + Map antiReplay = new HashMap<>(); + antiReplay.put("iat", 1234); + antiReplay.put("exp", 2345); + antiReplay.put("jti", "test-jti"); + metadata.put("antiReplay", antiReplay); + responsePayload.put("metadata", metadata); + } else { + responsePayload.put("metadata", null); + } + + Map response = new HashMap<>(); + response.put("type", "getCurrentContextResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", responsePayload); + return response; + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CloseResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CloseResponse.java new file mode 100644 index 00000000..0eb6419e --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CloseResponse.java @@ -0,0 +1,45 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.errors.CloseError; +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to close requests. + */ +public class CloseResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "closeRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map payload = new HashMap<>(); + + if (messaging.isCloseShouldFail()) { + payload.put("error", CloseError.ErrorOnClose.toString()); + } + + Map response = new HashMap<>(); + response.put("type", "closeResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CreatePrivateChannelResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CreatePrivateChannelResponse.java new file mode 100644 index 00000000..2b122bfe --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/CreatePrivateChannelResponse.java @@ -0,0 +1,50 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to createPrivateChannel requests. + */ +public class CreatePrivateChannelResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "createPrivateChannelRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + String channelId = "private-" + UUID.randomUUID().toString(); + + Map channel = new HashMap<>(); + channel.put("id", channelId); + channel.put("type", "private"); + + Map payload = new HashMap<>(); + payload.put("privateChannel", channel); + + Map response = new HashMap<>(); + response.put("type", "createPrivateChannelResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/DisconnectPrivateChannelResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/DisconnectPrivateChannelResponse.java new file mode 100644 index 00000000..d5bccc8b --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/DisconnectPrivateChannelResponse.java @@ -0,0 +1,40 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to privateChannelDisconnect requests. + */ +public class DisconnectPrivateChannelResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "privateChannelDisconnectRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + Map response = new HashMap<>(); + response.put("type", "privateChannelDisconnectResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindInstancesResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindInstancesResponse.java new file mode 100644 index 00000000..d723d85e --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindInstancesResponse.java @@ -0,0 +1,50 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to findInstances requests. + */ +public class FindInstancesResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "findInstancesRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + List> appIdentifiers = new ArrayList<>(); + appIdentifiers.add(Map.of("appId", "One", "instanceId", "1")); + appIdentifiers.add(Map.of("appId", "Two", "instanceId", "2")); + appIdentifiers.add(Map.of("appId", "Three", "instanceId", "3")); + + Map payload = new HashMap<>(); + payload.put("appIdentifiers", appIdentifiers); + + Map response = new HashMap<>(); + response.put("type", "findInstancesResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentByContextResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentByContextResponse.java new file mode 100644 index 00000000..6868d787 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentByContextResponse.java @@ -0,0 +1,93 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.IntentDetail; + +/** + * Responds to findIntentsByContext requests. + */ +public class FindIntentByContextResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "findIntentsByContextRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + + Map context = (Map) msgPayload.get("context"); + String contextType = context != null ? (String) context.get("type") : null; + + // Find matching intent details by context type + List matching = new ArrayList<>(); + for (IntentDetail detail : messaging.getIntentDetails()) { + if (contextType == null || contextType.equals(detail.getContext())) { + matching.add(detail); + } + } + + // Get unique intent names + Set uniqueIntents = new LinkedHashSet<>(); + for (IntentDetail detail : matching) { + if (detail.getIntent() != null) { + uniqueIntents.add(detail.getIntent()); + } + } + + // Build appIntents + List> appIntents = new ArrayList<>(); + for (String intentName : uniqueIntents) { + Map intentInfo = new LinkedHashMap<>(); + intentInfo.put("name", intentName); + intentInfo.put("displayName", intentName); + + List> apps = new ArrayList<>(); + for (IntentDetail detail : matching) { + if (intentName.equals(detail.getIntent()) && detail.getApp() != null) { + Map app = new LinkedHashMap<>(); + app.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { app.put("instanceId", detail.getApp().getInstanceId()); } + apps.add(app); + } + } + + Map appIntent = new HashMap<>(); + appIntent.put("intent", intentInfo); + appIntent.put("apps", apps); + appIntents.add(appIntent); + } + + Map payload = new HashMap<>(); + payload.put("appIntents", appIntents); + + Map response = new HashMap<>(); + response.put("type", "findIntentsByContextResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentResponse.java new file mode 100644 index 00000000..ec14fa20 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/FindIntentResponse.java @@ -0,0 +1,118 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.IntentDetail; + +/** + * Responds to findIntent requests. + */ +public class FindIntentResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "findIntentRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + + String intent = (String) msgPayload.get("intent"); + Map context = (Map) msgPayload.get("context"); + String contextType = context != null ? (String) context.get("type") : null; + String resultType = (String) msgPayload.get("resultType"); + + // Find matching intent details + List matching = new ArrayList<>(); + for (IntentDetail detail : messaging.getIntentDetails()) { + if (intentDetailMatches(detail, intent, contextType, resultType)) { + matching.add(detail); + } + } + + // Build app list + List> apps = new ArrayList<>(); + for (IntentDetail detail : matching) { + if (detail.getApp() != null && detail.getApp().getAppId() != null) { + Map app = new HashMap<>(); + app.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { app.put("instanceId", detail.getApp().getInstanceId()); } + apps.add(app); + } + } + + Map intentInfo = new HashMap<>(); + intentInfo.put("name", intent); + intentInfo.put("displayName", intent); + + Map appIntent = new HashMap<>(); + appIntent.put("intent", intentInfo); + appIntent.put("apps", apps); + + Map payload = new HashMap<>(); + payload.put("appIntent", appIntent); + + Map response = new HashMap<>(); + response.put("type", "findIntentResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } + + private boolean intentDetailMatches(IntentDetail detail, String intent, String contextType, String resultType) { + // Match intent + if (intent != null && detail.getIntent() != null && !intent.equals(detail.getIntent())) { + return false; + } + + // Match context type (optional) + if (contextType != null && detail.getContext() != null && !contextType.equals(detail.getContext())) { + return false; + } + + // Match result type (optional, with generic handling) + if (resultType != null) { + String detailResultType = detail.getResultType(); + if (detailResultType == null) { + return false; + } + + // Handle generic types + if (resultType.contains("<")) { + if (!resultType.equals(detailResultType)) { + return false; + } + } else { + String actualType = removeGenericType(detailResultType); + if (!resultType.equals(actualType)) { + return false; + } + } + } + + return true; + } + + private String removeGenericType(String type) { + int start = type.indexOf('<'); + return start > 0 ? type.substring(0, start) : type; + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetAppMetadataResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetAppMetadataResponse.java new file mode 100644 index 00000000..11151933 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetAppMetadataResponse.java @@ -0,0 +1,52 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to getAppMetadata requests. + */ +public class GetAppMetadataResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "getAppMetadataRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + Map app = (Map) msgPayload.get("app"); + + String appId = app != null ? (String) app.get("appId") : "unknown"; + + Map appMetadata = new HashMap<>(); + appMetadata.put("appId", appId); + appMetadata.put("name", "Metadata Name"); + appMetadata.put("description", "Metadata Description"); + + Map payload = new HashMap<>(); + payload.put("appMetadata", appMetadata); + + Map response = new HashMap<>(); + response.put("type", "getAppMetadataResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetInfoResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetInfoResponse.java new file mode 100644 index 00000000..27e1cbe4 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetInfoResponse.java @@ -0,0 +1,58 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to getInfo requests. + */ +public class GetInfoResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "getInfoRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + Map appMetadata = new HashMap<>(); + appMetadata.put("appId", "cucumber-app"); + appMetadata.put("instanceId", "cucumber-instance"); + + Map optionalFeatures = new HashMap<>(); + optionalFeatures.put("DesktopAgentBridging", false); + optionalFeatures.put("UserChannelMembershipAPIs", true); + + Map implementationMetadata = new HashMap<>(); + implementationMetadata.put("appMetadata", appMetadata); + implementationMetadata.put("fdc3Version", "2.0"); + implementationMetadata.put("optionalFeatures", optionalFeatures); + implementationMetadata.put("provider", "cucumber-provider"); + implementationMetadata.put("providerVersion", "test"); + + Map payload = new HashMap<>(); + payload.put("implementationMetadata", implementationMetadata); + + Map response = new HashMap<>(); + response.put("type", "getInfoResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetOrCreateChannelResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetOrCreateChannelResponse.java new file mode 100644 index 00000000..fd48e8e3 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetOrCreateChannelResponse.java @@ -0,0 +1,69 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to getOrCreateChannel requests. + */ +public class GetOrCreateChannelResponse implements AutomaticResponse { + + private final Map channelTypes = new ConcurrentHashMap<>(); + + @Override + public boolean filter(String messageType) { + return "getOrCreateChannelRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + String channelId = (String) msgPayload.get("channelId"); + String type = "app"; + + String existingType = channelTypes.get(channelId); + + Map payload = new HashMap<>(); + + if (existingType != null && !existingType.equals(type)) { + // channel already exists with different type + payload.put("error", "AccessDenied"); + } else { + channelTypes.put(channelId, type); + + Map channel = new HashMap<>(); + channel.put("id", channelId); + channel.put("type", type); + + Map displayMetadata = new HashMap<>(); + displayMetadata.put("name", "The " + channelId + " Channel"); + displayMetadata.put("color", "cerulean blue"); + displayMetadata.put("glyph", "triangle"); + channel.put("displayMetadata", displayMetadata); + + payload.put("channel", channel); + } + + Map response = new HashMap<>(); + response.put("type", "getOrCreateChannelResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetUserChannelsResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetUserChannelsResponse.java new file mode 100644 index 00000000..148cfd08 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/GetUserChannelsResponse.java @@ -0,0 +1,60 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to getUserChannels requests. + */ +public class GetUserChannelsResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "getUserChannelsRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + + List> userChannels = new ArrayList<>(); + for (String channelId : messaging.getChannelState().keySet()) { + Map channel = new HashMap<>(); + channel.put("id", channelId); + channel.put("type", "user"); + + Map displayMetadata = new HashMap<>(); + displayMetadata.put("name", "The " + channelId + " channel"); + displayMetadata.put("color", "red"); + displayMetadata.put("glyph", "triangle"); + channel.put("displayMetadata", displayMetadata); + + userChannels.add(channel); + } + + Map payload = new HashMap<>(); + payload.put("userChannels", userChannels); + + Map response = new HashMap<>(); + response.put("type", "getUserChannelsResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/IntentResultResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/IntentResultResponse.java new file mode 100644 index 00000000..d52bcff8 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/IntentResultResponse.java @@ -0,0 +1,60 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.PossibleIntentResult; + +/** + * Responds to intentResult requests. + */ +public class IntentResultResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "intentResultRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + + // Store the intent result from the request + Map intentResultPayload = (Map) msgPayload.get("intentResult"); + if (intentResultPayload != null) { + PossibleIntentResult result = new PossibleIntentResult(); + + Map contextMap = (Map) intentResultPayload.get("context"); + if (contextMap != null) { + Context context = Context.fromMap(contextMap); + result.setContext(context); + } + + // Note: channel handling would require a Channel implementation + // For now, we just store what we can + + messaging.setIntentResult(result); + } + + Map response = new HashMap<>(); + response.put("type", "intentResultResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/OpenResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/OpenResponse.java new file mode 100644 index 00000000..e67c999f --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/OpenResponse.java @@ -0,0 +1,66 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.IntentDetail; + +/** + * Responds to open requests. + */ +public class OpenResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "openRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + Map app = (Map) msgPayload.get("app"); + + String appId = app != null ? (String) app.get("appId") : null; + + Map payload = new HashMap<>(); + + // Find the app in intent details + IntentDetail found = null; + for (IntentDetail detail : messaging.getIntentDetails()) { + if (detail.getApp() != null && appId != null && + appId.equals(detail.getApp().getAppId())) { + found = detail; + break; + } + } + + if (found != null && found.getApp() != null) { + Map appIdentifier = new HashMap<>(); + appIdentifier.put("appId", found.getApp().getAppId()); + appIdentifier.put("instanceId", "abc123"); + payload.put("appIdentifier", appIdentifier); + } else { + payload.put("error", "AppNotFound"); + } + + Map response = new HashMap<>(); + response.put("type", "openResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentForContextResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentForContextResponse.java new file mode 100644 index 00000000..d492b9aa --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentForContextResponse.java @@ -0,0 +1,225 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.IntentDetail; +import org.finos.fdc3.proxy.support.TestMessaging.PossibleIntentResult; + +/** + * Responds to raiseIntentForContext requests. + */ +public class RaiseIntentForContextResponse implements AutomaticResponse { + + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "fdc3-test-raise-intent-for-context"); + t.setDaemon(true); + return t; + }); + + @Override + public boolean filter(String messageType) { + return "raiseIntentForContextRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + + Map context = (Map) msgPayload.get("context"); + String contextType = context != null ? (String) context.get("type") : null; + Map targetApp = (Map) msgPayload.get("app"); + + PossibleIntentResult intentResult = messaging.getIntentResult(); + + if (intentResult == null) { + // Figure out response based on app details + List matching = findMatchingIntents(messaging, contextType, targetApp); + Map response = createRaiseIntentForContextResponse(meta, matching, messaging); + scheduleReceive(messaging, response); + } else if (!intentResult.isTimeout()) { + // Send pre-set intent resolution + Map response = createCannedResponse(meta, messaging); + scheduleReceive(messaging, response); + + // Then send the result response + if (intentResult.getError() == null) { + Map resultResponse = createRaiseIntentResultResponse(meta, messaging); + if (resultResponse != null) { + scheduler.schedule(() -> { + messaging.receive(resultResponse, null); + }, 300, TimeUnit.MILLISECONDS); + } + } + } + + return CompletableFuture.completedFuture(null); + } + + private List findMatchingIntents(TestMessaging messaging, String contextType, + Map targetApp) { + List matching = new ArrayList<>(); + for (IntentDetail detail : messaging.getIntentDetails()) { + boolean matches = true; + + // Match context type - null is a wildcard that matches anything + // If either contextType (from request) or detail.getContext() is null, it matches + if (contextType != null && detail.getContext() != null && !contextType.equals(detail.getContext())) { + matches = false; + } + + // Match target app if specified + if (matches && targetApp != null && detail.getApp() != null) { + String targetAppId = (String) targetApp.get("appId"); + String targetInstanceId = (String) targetApp.get("instanceId"); + if (targetAppId != null && !targetAppId.equals(detail.getApp().getAppId())) { + matches = false; + } + if (matches && targetInstanceId != null && + detail.getApp().getInstanceId() != null && + !targetInstanceId.equals(detail.getApp().getInstanceId())) { + matches = false; + } + } + + if (matches) { + matching.add(detail); + } + } + return matching; + } + + private Map createRaiseIntentForContextResponse(Map meta, + List relevant, + TestMessaging messaging) { + Map payload = new HashMap<>(); + + if (relevant.isEmpty()) { + payload.put("error", "NoAppsFound"); + } else if (relevant.size() == 1 && relevant.get(0).getIntent() != null && relevant.get(0).getApp() != null) { + IntentDetail detail = relevant.get(0); + Map source = new HashMap<>(); + source.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { source.put("instanceId", detail.getApp().getInstanceId()); } + + Map resolution = new HashMap<>(); + resolution.put("intent", detail.getIntent()); + resolution.put("source", source); + payload.put("intentResolution", resolution); + } else { + // Multiple intents found - return appIntents for disambiguation + Set uniqueIntents = new LinkedHashSet<>(); + for (IntentDetail detail : relevant) { + if (detail.getIntent() != null) { + uniqueIntents.add(detail.getIntent()); + } + } + + List> appIntents = new ArrayList<>(); + for (String intentName : uniqueIntents) { + Map intentInfo = new LinkedHashMap<>(); + intentInfo.put("name", intentName); + intentInfo.put("displayName", intentName); + + List> apps = new ArrayList<>(); + for (IntentDetail detail : relevant) { + if (intentName.equals(detail.getIntent()) && detail.getApp() != null) { + Map app = new LinkedHashMap<>(); + app.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { app.put("instanceId", detail.getApp().getInstanceId()); } + apps.add(app); + } + } + + Map appIntent = new LinkedHashMap<>(); + appIntent.put("intent", intentInfo); + appIntent.put("apps", apps); + appIntents.add(appIntent); + } + + payload.put("appIntents", appIntents); + } + + Map response = new HashMap<>(); + response.put("type", "raiseIntentForContextResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } + + private Map createCannedResponse(Map meta, TestMessaging messaging) { + PossibleIntentResult result = messaging.getIntentResult(); + + Map payload = new HashMap<>(); + + if (result != null && result.getError() != null) { + payload.put("error", result.getError()); + } else { + Map source = new HashMap<>(); + source.put("appId", "some-app"); + source.put("instanceId", "abc123"); + + Map resolution = new HashMap<>(); + resolution.put("intent", "some-canned-intent"); + resolution.put("source", source); + payload.put("intentResolution", resolution); + } + + Map response = new HashMap<>(); + response.put("type", "raiseIntentForContextResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } + + private Map createRaiseIntentResultResponse(Map meta, TestMessaging messaging) { + PossibleIntentResult result = messaging.getIntentResult(); + if (result == null || result.getError() != null) { + return null; + } + + Map intentResult = new HashMap<>(); + if (result.getContext() != null) { + intentResult.put("context", result.getContext()); + } + if (result.getChannel() != null) { + Map channelMap = new HashMap<>(); + channelMap.put("id", result.getChannel().getId()); + channelMap.put("type", result.getChannel().getType()); + intentResult.put("channel", channelMap); + } + + Map payload = new HashMap<>(); + payload.put("intentResult", intentResult); + + Map response = new HashMap<>(); + response.put("type", "raiseIntentResultResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentResponse.java new file mode 100644 index 00000000..6637f384 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RaiseIntentResponse.java @@ -0,0 +1,227 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.finos.fdc3.proxy.support.TestMessaging; +import org.finos.fdc3.proxy.support.TestMessaging.IntentDetail; +import org.finos.fdc3.proxy.support.TestMessaging.PossibleIntentResult; + +/** + * Responds to raiseIntent requests. + */ +public class RaiseIntentResponse implements AutomaticResponse { + + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "fdc3-test-raise-intent"); + t.setDaemon(true); + return t; + }); + + @Override + public boolean filter(String messageType) { + return "raiseIntentRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + Map meta = (Map) message.get("meta"); + Map msgPayload = (Map) message.get("payload"); + + String intent = (String) msgPayload.get("intent"); + Map context = (Map) msgPayload.get("context"); + String contextType = context != null ? (String) context.get("type") : null; + Map targetApp = (Map) msgPayload.get("app"); + + PossibleIntentResult intentResult = messaging.getIntentResult(); + + if (intentResult == null) { + // Figure out response based on app details (like FindIntent) + List matching = findMatchingIntents(messaging, intent, contextType, targetApp); + Map response = createRaiseIntentResponse(meta, message, matching, messaging); + scheduleReceive(messaging, response); + } else if (!intentResult.isTimeout()) { + // Send pre-set intent resolution + Map response = createCannedRaiseIntentResponse(meta, message, messaging); + scheduleReceive(messaging, response); + + // Then send the result response + if (intentResult.getError() == null) { + Map resultResponse = createRaiseIntentResultResponse(meta, messaging); + if (resultResponse != null) { + scheduler.schedule(() -> { + messaging.receive(resultResponse, null); + }, 300, TimeUnit.MILLISECONDS); + } + } + } + + return CompletableFuture.completedFuture(null); + } + + private List findMatchingIntents(TestMessaging messaging, String intent, + String contextType, Map targetApp) { + List matching = new ArrayList<>(); + for (IntentDetail detail : messaging.getIntentDetails()) { + boolean matches = true; + + // Match intent name + if (intent != null && detail.getIntent() != null && !intent.equals(detail.getIntent())) { + matches = false; + } + + // Match context type when the request includes a context + if (matches && contextType != null && detail.getContext() != null + && !contextType.equals(detail.getContext())) { + matches = false; + } + + // Match target app if specified + if (matches && targetApp != null && detail.getApp() != null) { + String targetAppId = (String) targetApp.get("appId"); + String targetInstanceId = (String) targetApp.get("instanceId"); + if (targetAppId != null && !targetAppId.equals(detail.getApp().getAppId())) { + matches = false; + } + if (matches && targetInstanceId != null && + detail.getApp().getInstanceId() != null && + !targetInstanceId.equals(detail.getApp().getInstanceId())) { + matches = false; + } + } + + if (matches) { + matching.add(detail); + } + } + return matching; + } + + @SuppressWarnings("unchecked") + private Map createRaiseIntentResponse(Map meta, Map message, + List relevant, TestMessaging messaging) { + Map msgPayload = (Map) message.get("payload"); + String intent = (String) msgPayload.get("intent"); + + Map payload = new HashMap<>(); + + if (relevant.isEmpty()) { + payload.put("error", "NoAppsFound"); + } else if (relevant.size() == 1 && relevant.get(0).getIntent() != null && relevant.get(0).getApp() != null) { + IntentDetail detail = relevant.get(0); + Map source = new HashMap<>(); + source.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { source.put("instanceId", detail.getApp().getInstanceId()); } + + Map resolution = new HashMap<>(); + resolution.put("intent", detail.getIntent()); + resolution.put("source", source); + payload.put("intentResolution", resolution); + } else { + // Multiple apps found - return appIntent for disambiguation + List> apps = new ArrayList<>(); + for (IntentDetail detail : relevant) { + if (detail.getApp() != null && detail.getApp().getAppId() != null) { + Map app = new HashMap<>(); + app.put("appId", detail.getApp().getAppId()); + if (detail.getApp().getInstanceId() != null) { app.put("instanceId", detail.getApp().getInstanceId()); } + apps.add(app); + } + } + + Map intentInfo = new HashMap<>(); + intentInfo.put("name", intent); + intentInfo.put("displayName", intent); + + Map appIntent = new HashMap<>(); + appIntent.put("intent", intentInfo); + appIntent.put("apps", apps); + payload.put("appIntent", appIntent); + } + + Map response = new HashMap<>(); + response.put("type", "raiseIntentResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } + + @SuppressWarnings("unchecked") + private Map createCannedRaiseIntentResponse(Map meta, + Map message, + TestMessaging messaging) { + PossibleIntentResult result = messaging.getIntentResult(); + Map msgPayload = (Map) message.get("payload"); + String intent = (String) msgPayload.get("intent"); + + Map payload = new HashMap<>(); + + if (result != null && result.getError() != null) { + payload.put("error", result.getError()); + } else { + Map source = new HashMap<>(); + source.put("appId", "some-app"); + source.put("instanceId", "abc123"); + + Map resolution = new HashMap<>(); + resolution.put("intent", intent); + resolution.put("source", source); + payload.put("intentResolution", resolution); + } + + Map response = new HashMap<>(); + response.put("type", "raiseIntentResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } + + private Map createRaiseIntentResultResponse(Map meta, TestMessaging messaging) { + PossibleIntentResult result = messaging.getIntentResult(); + if (result == null || result.getError() != null) { + return null; + } + + Map intentResult = new HashMap<>(); + if (result.getContext() != null) { + intentResult.put("context", result.getContext()); + } + if (result.getChannel() != null) { + Map channelMap = new HashMap<>(); + channelMap.put("id", result.getChannel().getId()); + channelMap.put("type", result.getChannel().getType()); + intentResult.put("channel", channelMap); + } + + Map payload = new HashMap<>(); + payload.put("intentResult", intentResult); + if (result.getResultMetadata() != null) { + payload.put("resultMetadata", messaging.getConverter().convertValue( + result.getResultMetadata(), Map.class)); + } + + Map response = new HashMap<>(); + response.put("type", "raiseIntentResultResponse"); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + return response; + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RegisterListenersResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RegisterListenersResponse.java new file mode 100644 index 00000000..0cd4f0c2 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/RegisterListenersResponse.java @@ -0,0 +1,50 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to listener registration requests. + */ +public class RegisterListenersResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "addContextListenerRequest".equals(messageType) || + "addIntentListenerRequest".equals(messageType) || + "addEventListenerRequest".equals(messageType) || + "privateChannelAddEventListenerRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + String type = (String) message.get("type"); + String responseType = type.replace("Request", "Response"); + + Map meta = (Map) message.get("meta"); + + Map payload = new HashMap<>(); + payload.put("listenerUUID", UUID.randomUUID().toString()); + + Map response = new HashMap<>(); + response.put("type", responseType); + response.put("meta", createResponseMeta(meta)); + response.put("payload", payload); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ResponseSupport.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ResponseSupport.java new file mode 100644 index 00000000..27f005c1 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/ResponseSupport.java @@ -0,0 +1,49 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Support utilities for creating test responses. + */ +public class ResponseSupport { + + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "fdc3-test-response-scheduler"); + t.setDaemon(true); + return t; + }); + + /** + * Creates response metadata from request metadata. + */ + public static Map createResponseMeta(Map requestMeta) { + Map meta = new HashMap<>(); + meta.put("requestUuid", requestMeta.get("requestUuid")); + meta.put("responseUuid", UUID.randomUUID().toString()); + meta.put("source", requestMeta.get("source")); + meta.put("timestamp", Instant.now().toString()); + return meta; + } + + /** + * Schedules a response to be sent after a short delay. + * This simulates async message delivery. + */ + public static void scheduleReceive(TestMessaging messaging, Map response) { + scheduler.schedule(() -> { + messaging.receive(response, null); + }, 100, TimeUnit.MILLISECONDS); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/UnsubscribeListenersResponse.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/UnsubscribeListenersResponse.java new file mode 100644 index 00000000..12370640 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/support/responses/UnsubscribeListenersResponse.java @@ -0,0 +1,46 @@ +/** + * Copyright FINOS and its Contributors + */ +package org.finos.fdc3.proxy.support.responses; + +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.createResponseMeta; +import static org.finos.fdc3.proxy.support.responses.ResponseSupport.scheduleReceive; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.proxy.support.TestMessaging; + +/** + * Responds to listener unsubscribe requests. + */ +public class UnsubscribeListenersResponse implements AutomaticResponse { + + @Override + public boolean filter(String messageType) { + return "contextListenerUnsubscribeRequest".equals(messageType) || + "intentListenerUnsubscribeRequest".equals(messageType) || + "eventListenerUnsubscribeRequest".equals(messageType) || + "privateChannelUnsubscribeEventListenerRequest".equals(messageType); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage action(Map message, TestMessaging messaging) { + String type = (String) message.get("type"); + String responseType = type.replace("Request", "Response"); + + Map meta = (Map) message.get("meta"); + + Map response = new HashMap<>(); + response.put("type", responseType); + response.put("meta", createResponseMeta(meta)); + response.put("payload", new HashMap<>()); + + scheduleReceive(messaging, response); + return CompletableFuture.completedFuture(null); + } +} + diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/util/ThrowIfUndefinedTest.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/util/ThrowIfUndefinedTest.java new file mode 100644 index 00000000..eed0f021 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/util/ThrowIfUndefinedTest.java @@ -0,0 +1,98 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.util; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.errors.ChannelError; +import org.junit.jupiter.api.Test; + +/** + * Covers the guard every receive path uses when a Desktop Agent sends a response that is missing + * a property the proxy needs. + *

+ * Without this guard a malformed message produces a {@code NullPointerException} somewhere later, + * which tells an application nothing. The contract is that the property's absence surfaces + * immediately as the FDC3 error name the caller can match on. + */ +class ThrowIfUndefinedTest { + + private static Map message(Object payload) { + Map message = new HashMap<>(); + message.put("type", "getOrCreateChannelResponse"); + message.put("payload", payload); + return message; + } + + @Test + void absentPropertyThrowsTheFdc3ErrorName() { + RuntimeException thrown = assertThrows(RuntimeException.class, + () -> ThrowIfUndefined.throwIfUndefined( + null, + "No channel returned", + message(new HashMap<>()), + ChannelError.NoChannelFound.toString())); + + // The message must be the bare error name: callers match on it, and anything else + // (a sentence, a class name, a wrapped cause) breaks that. + assertEquals("NoChannelFound", thrown.getMessage()); + } + + @Test + void presentPropertyDoesNotThrow() { + assertDoesNotThrow(() -> ThrowIfUndefined.throwIfUndefined( + "channel-1", + "No channel returned", + message(Map.of("channel", "channel-1")), + ChannelError.NoChannelFound.toString())); + } + + @Test + void falseAndEmptyAreStillPresentValues() { + // Only absence is a failure. A legitimately false or empty value must pass, or the + // guard would reject valid responses such as an empty channel-context list. + assertDoesNotThrow(() -> ThrowIfUndefined.throwIfUndefined( + Boolean.FALSE, "absent", message(new HashMap<>()), "ShouldNotThrow")); + assertDoesNotThrow(() -> ThrowIfUndefined.throwIfUndefined( + "", "absent", message(new HashMap<>()), "ShouldNotThrow")); + } + + @Test + void aMessageThatIsNotAMapStillReportsTheError() { + // Some call sites hold a typed message object rather than a map. Diagnostics must + // degrade rather than throw something unrelated from the logging path. + RuntimeException thrown = assertThrows(RuntimeException.class, + () -> ThrowIfUndefined.throwIfUndefined( + null, "No listener UUID returned", new Object(), "MalformedMessage")); + + assertEquals("MalformedMessage", thrown.getMessage()); + } + + @Test + void aNullMessageStillReportsTheError() { + RuntimeException thrown = assertThrows(RuntimeException.class, + () -> ThrowIfUndefined.throwIfUndefined( + null, "Nothing to report against", null, "MalformedMessage")); + + assertEquals("MalformedMessage", thrown.getMessage()); + } +} diff --git a/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/world/CustomWorld.java b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/world/CustomWorld.java new file mode 100644 index 00000000..23b49c62 --- /dev/null +++ b/fdc3-agent-proxy/src/test/java/org/finos/fdc3/proxy/world/CustomWorld.java @@ -0,0 +1,73 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.proxy.world; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.proxy.support.TestMessaging; + +import org.finos.cucumbertestingsteps.world.PropsWorld; + +/** + * Custom Cucumber World for agent-proxy tests. + * Extends PropsWorld and adds messaging support. + * + * Bean configuration in TestSpringConfig ensures the same instance is shared + * across all step definition classes within a scenario. + */ +public class CustomWorld extends PropsWorld { + + private TestMessaging messaging; + + /** + * cucumber-testing-steps stores invocation counters as {@link Runnable}, but FDC3 + * event listener APIs require {@link EventHandler}. Adapt on lookup so feature + * files can keep the canonical step wording unchanged. + */ + @Override + public Object get(String key) { + return adaptInvocationCounter(super.get(key)); + } + + @Override + public Object get(Object key) { + if (key instanceof String) { + return get((String) key); + } + return adaptInvocationCounter(super.get(key)); + } + + private static Object adaptInvocationCounter(Object value) { + if (value instanceof Runnable && !(value instanceof EventHandler)) { + Runnable runnable = (Runnable) value; + return (EventHandler) event -> runnable.run(); + } + return value; + } + + public TestMessaging getMessaging() { + return messaging; + } + + public void setMessaging(TestMessaging messaging) { + this.messaging = messaging; + } + + public boolean hasMessaging() { + return messaging != null; + } +} + diff --git a/fdc3-context/pom.xml b/fdc3-context/pom.xml new file mode 100644 index 00000000..bdf260e2 --- /dev/null +++ b/fdc3-context/pom.xml @@ -0,0 +1,345 @@ + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-context + FDC3 Context Types + Generated Java classes for FDC3 Context types from JSON Schema + + + ${project.build.directory}/schemas-work + + ${project.build.directory}/npm-work/node_modules/@finos/fdc3-context/dist/schemas/context + ${project.build.directory}/npm-work/node_modules/@finos/fdc3-schema/dist/schemas/api + + ${project.basedir}/../fdc3-schema/src/main/schemas-overlay/api + + ${fdc3.context.schemas.work.dir}/context + ${fdc3.context.schemas.work.dir}/api/api.schema.json + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + none + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + create-directories + initialize + + run + + + + + + + + + + + + + + + + + + clean-generated-sources + generate-sources + + run + + + + + + + + + + + + purge-stale-handwritten-classes + process-classes + + run + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.release} + + false + + + + default-compile + + + ${project.build.directory}/generated-sources/fdc3 + + + + + + compile-handwritten-sources + process-classes + + compile + + + + ${project.basedir}/src/main/java + + + + + + + + + com.github.eirslett + frontend-maven-plugin + 1.15.0 + + ${node.version} + ${npm.version} + ${project.build.directory}/npm-work + ${project.build.directory}/node-installation + + + + + install-node-and-npm + generate-sources + + install-node-and-npm + + + + + npm-ci + generate-sources + + npm + + + ci --no-audit --no-fund + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + populate-schemas-work + generate-sources + + copy-resources + + + ${fdc3.context.schemas.work.dir} + true + + + ${fdc3.context.npm.dir} + context + + + ${fdc3.api.npm.dir} + api + + + + + + copy-api-overlay + generate-sources + + copy-resources + + + ${fdc3.context.schemas.work.dir} + true + + + ${fdc3.api.overlay.dir} + api + + README.md + + + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.1 + + + quicktype-context + generate-sources + + exec + + + /bin/sh + ${project.build.directory}/npm-work + + -c + ${project.build.directory}/node-installation/node/node node_modules/quicktype/dist/index.js -s schema --quiet --lang java --package org.finos.fdc3.context --out ${project.build.directory}/generated-sources/fdc3/org/finos/fdc3/context/ContextTypes.java -S ${fdc3.api.schema.path} $(find ${fdc3.context.source.dir} -name "*.schema.json" -exec printf "%s %s " "--src" {} \;) + + + + + + fix-context-imports + generate-sources + + exec + + + sh + + ${project.basedir}/scripts/fix-context-imports.sh + ${project.build.directory}/generated-sources/fdc3/org/finos/fdc3/context + + + + + + verify-generated-classes + test-compile + + exec + + + sh + + -c + missing=0; for c in ActionType NothingType EmailRecipients ChartStyle; do \ + if [ ! -f "${project.build.directory}/classes/org/finos/fdc3/context/$c.class" ]; then \ + echo "Missing compiled class: org.finos.fdc3.context.$c"; missing=1; \ + fi; \ + done; exit $missing + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.3 + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.4.0 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/fdc3 + + + + + + + + diff --git a/fdc3-context/scripts/fix-context-imports.sh b/fdc3-context/scripts/fix-context-imports.sh new file mode 100644 index 00000000..55c1f31e --- /dev/null +++ b/fdc3-context/scripts/fix-context-imports.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Copyright FINOS FDC3 contributors - see NOTICE file +# +# Post-process quicktype Java output: remove duplicate Context types and fix imports. + +set -eu + +cd "${1:?usage: fix-context-imports.sh }" + +rm -f Context.java ContextElement.java 2>/dev/null || true + +for f in *.java; do + [ -f "$f" ] || continue + # Cross-platform in-place edit (GNU sed vs BSD sed) + if sed --version 2>/dev/null | grep -q GNU; then + sed -i -e 's/ContextElement/Context/g' "$f" + if grep -qE '(private|public) Context |Context get|Context\[\]|ContextFromJsonString|List|Map<[^>]*Context>' "$f"; then + sed -i '/^package org.finos.fdc3.context;$/a\ +import org.finos.fdc3.api.context.Context;' "$f" + fi + else + sed -i '' -e 's/ContextElement/Context/g' "$f" + if grep -qE '(private|public) Context |Context get|Context\[\]|ContextFromJsonString|List|Map<[^>]*Context>' "$f"; then + sed -i '' '/^package org.finos.fdc3.context;$/a\ +import org.finos.fdc3.api.context.Context;' "$f" + fi + fi +done diff --git a/fdc3-context/src/main/java/org/finos/fdc3/context/ContextConverter.java b/fdc3-context/src/main/java/org/finos/fdc3/context/ContextConverter.java new file mode 100644 index 00000000..deb64d50 --- /dev/null +++ b/fdc3-context/src/main/java/org/finos/fdc3/context/ContextConverter.java @@ -0,0 +1,173 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.context; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.finos.fdc3.api.context.Context; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Utility class for converting JSON to the appropriate FDC3 context type + * based on the "type" field in the JSON. + */ +public class ContextConverter { + + private static final ObjectMapper mapper = createObjectMapper(); + + private static ObjectMapper createObjectMapper() { + ObjectMapper om = new ObjectMapper(); + // Register Java 8 date/time module + om.registerModule(new JavaTimeModule()); + // Don't fail on unknown properties (FDC3 allows additional properties) + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // Write dates as ISO strings, not timestamps + om.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + return om; + } + + // Map of FDC3 type strings to their corresponding Java classes + private static final Map> TYPE_MAP = new HashMap<>(); + + static { + TYPE_MAP.put("fdc3.action", Action.class); + TYPE_MAP.put("fdc3.chart", Chart.class); + TYPE_MAP.put("fdc3.chat.initSettings", ChatInitSettings.class); + TYPE_MAP.put("fdc3.chat.message", ChatMessage.class); + TYPE_MAP.put("fdc3.chat.room", ChatRoom.class); + TYPE_MAP.put("fdc3.chat.searchCriteria", ChatSearchCriteria.class); + TYPE_MAP.put("fdc3.contact", Contact.class); + TYPE_MAP.put("fdc3.contactList", ContactList.class); + TYPE_MAP.put("fdc3.context", Context.class); + TYPE_MAP.put("fdc3.country", Country.class); + TYPE_MAP.put("fdc3.currency", Currency.class); + TYPE_MAP.put("fdc3.email", Email.class); + TYPE_MAP.put("fdc3.fileAttachment", FileAttachment.class); + TYPE_MAP.put("fdc3.instrument", Instrument.class); + TYPE_MAP.put("fdc3.instrumentList", InstrumentList.class); + TYPE_MAP.put("fdc3.interaction", Interaction.class); + TYPE_MAP.put("fdc3.message", Message.class); + TYPE_MAP.put("fdc3.nothing", Nothing.class); + TYPE_MAP.put("fdc3.order", Order.class); + TYPE_MAP.put("fdc3.orderList", OrderList.class); + TYPE_MAP.put("fdc3.organization", Organization.class); + TYPE_MAP.put("fdc3.portfolio", Portfolio.class); + TYPE_MAP.put("fdc3.position", Position.class); + TYPE_MAP.put("fdc3.product", Product.class); + TYPE_MAP.put("fdc3.security.encryptedContext", EncryptedContextWrapper.class); + TYPE_MAP.put("fdc3.security.symmetricKeyRequest", SymmetricKeyRequest.class); + TYPE_MAP.put("fdc3.security.symmetricKeyResponse", SymmetricKeyResponse.class); + TYPE_MAP.put("fdc3.security.user", User.class); + TYPE_MAP.put("fdc3.security.userRequest", UserRequest.class); + TYPE_MAP.put("fdc3.timeRange", TimeRange.class); + TYPE_MAP.put("fdc3.trade", Trade.class); + TYPE_MAP.put("fdc3.tradeList", TradeList.class); + TYPE_MAP.put("fdc3.transactionResult", TransactionResult.class); + TYPE_MAP.put("fdc3.valuation", Valuation.class); + } + + /** + * Get the Java class for a given FDC3 type string. + * + * @param fdc3Type the FDC3 type string (e.g., "fdc3.contact") + * @return the corresponding Java class, or null if not found + */ + public static Class getClassForType(String fdc3Type) { + return TYPE_MAP.get(fdc3Type); + } + + /** + * Parse a JSON string and return the appropriate context object based on the "type" field. + * + * @param json the JSON string to parse + * @return the parsed context object + * @throws IOException if parsing fails + * @throws IllegalArgumentException if the type is unknown + */ + public static Object fromJson(String json) throws IOException { + JsonNode node = mapper.readTree(json); + String type = node.has("type") ? node.get("type").asText() : null; + + if (type == null) { + throw new IllegalArgumentException("JSON does not contain a 'type' field"); + } + + Class clazz = TYPE_MAP.get(type); + if (clazz == null) { + throw new IllegalArgumentException("Unknown context type: " + type); + } + + return mapper.treeToValue(node, clazz); + } + + /** + * Parse a JSON string into a specific context class. + * + * @param json the JSON string to parse + * @param clazz the target class + * @param the type of the context + * @return the parsed context object + * @throws IOException if parsing fails + */ + public static T fromJson(String json, Class clazz) throws IOException { + return mapper.readValue(json, clazz); + } + + /** + * Serialize a context object to JSON. + * + * @param context the context object to serialize + * @return the JSON string + * @throws JsonProcessingException if serialization fails + */ + public static String toJson(Object context) throws JsonProcessingException { + return mapper.writeValueAsString(context); + } + + /** + * Serialize a context object to pretty-printed JSON. + * + * @param context the context object to serialize + * @return the pretty-printed JSON string + * @throws JsonProcessingException if serialization fails + */ + public static String toJsonPretty(Object context) throws JsonProcessingException { + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(context); + } + + /** + * Check if two JSON strings are semantically equivalent (same content, possibly different formatting). + * + * @param json1 first JSON string + * @param json2 second JSON string + * @return true if the JSON objects are equivalent + * @throws IOException if parsing fails + */ + public static boolean jsonEquals(String json1, String json2) throws IOException { + JsonNode node1 = mapper.readTree(json1); + JsonNode node2 = mapper.readTree(json2); + return node1.equals(node2); + } +} + diff --git a/fdc3-context/src/main/npm/package-lock.json b/fdc3-context/src/main/npm/package-lock.json new file mode 100644 index 00000000..95f8897c --- /dev/null +++ b/fdc3-context/src/main/npm/package-lock.json @@ -0,0 +1,1242 @@ +{ + "name": "fdc3-context-codegen", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fdc3-context-codegen", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-context": "3.0.0-alpha.5", + "@finos/fdc3-schema": "3.0.0-alpha.5", + "quicktype": "26.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@finos/fdc3-context": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-context/-/fdc3-context-3.0.0-alpha.5.tgz", + "integrity": "sha512-VN2LEmWvqLz4xsfXEsqcMNJjxD97/oyh7uPOwHmapoIuc0aW0YS9750tbcCf9GqC3XKnaca+itSW+rhlStJNvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@finos/fdc3-schema": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-schema/-/fdc3-schema-3.0.0-alpha.5.tgz", + "integrity": "sha512-LAKu4HEpQ+UNDco/1ehObiO+QqHoOmGFCP8dk5EerA/2XL0ki6bTFoM0E9ZaGeOQcxz9ifRAJrRDiiYzVi21Bg==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.4.0.tgz", + "integrity": "sha512-mDC+qosuNa4lxR3ioMBb6CD0XLRsQBplU+zRPUYiMLXKeVPZ6UYphdNG/EGReig0YyfnVlBKZEXl1wzTotYmPA==", + "license": "MIT" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", + "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/readable-stream": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", + "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/urijs": { + "version": "1.19.26", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", + "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "license": "Apache-2.0" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.4.tgz", + "integrity": "sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==", + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.1", + "typical": "^7.3.0" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.3.tgz", + "integrity": "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graphql": { + "version": "16.14.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz", + "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", + "integrity": "sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/path-equal": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.8.tgz", + "integrity": "sha512-rCJWMlXlk9lZ2FEllgvh2IgPj/kxMx2sOeqtFNLO8dxEY0I4hBTa+ZW3JAsgeiTe8vL4MifATVDwxF9nGUI7HQ==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/quicktype": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype/-/quicktype-26.0.0.tgz", + "integrity": "sha512-6sGRYEe3402KFTVKhqnsE6Z6Jdi5jryc/6cg+A8kx3dvIy01Ex35OcuuuZUZDbvzFw+1fkseCpLpbGhDS3uLJA==", + "license": "Apache-2.0", + "workspaces": [ + "./packages/quicktype-core", + "./packages/quicktype-graphql-input", + "./packages/quicktype-typescript-input", + "./packages/quicktype-vscode" + ], + "dependencies": { + "@glideapps/ts-necessities": "^2.2.3", + "@types/readable-stream": "4.0.10", + "chalk": "^4.1.2", + "collection-utils": "^1.0.1", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1", + "graphql": "^16.11.0", + "lodash": "^4.18.1", + "moment": "^2.30.1", + "quicktype-core": "26.0.0", + "quicktype-graphql-input": "26.0.0", + "quicktype-typescript-input": "26.0.0", + "readable-stream": "^4.5.2", + "stream-json": "3.5.0", + "string-to-stream": "^3.0.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "quicktype": "dist/index.js" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/quicktype-core": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-26.0.0.tgz", + "integrity": "sha512-tLSe2RkSj7c7ocTc+QMuQDGgEetGhZvKXLv1vNwpAQX2x8oOGYU9KSgJdIP9Qvy5hm47S2k3ZAX1LQAdS75JaA==", + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "@types/readable-stream": "4.0.10", + "@types/urijs": "^1.19.26", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "is-url": "^1.2.4", + "lodash": "^4.18.1", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.9.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/quicktype-core/node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "license": "MIT" + }, + "node_modules/quicktype-core/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/quicktype-graphql-input": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-graphql-input/-/quicktype-graphql-input-26.0.0.tgz", + "integrity": "sha512-bI129FVf6LLrG+6rh0gB9905oqNN0oGuZYIS0gV3V3C4JEdaR2qavdM/r925pUISwM3frrYE4McSDsuAzrHRTw==", + "license": "Apache-2.0", + "dependencies": { + "collection-utils": "^1.0.1", + "graphql": "^16.11.0", + "quicktype-core": "26.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/quicktype-typescript-input": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-typescript-input/-/quicktype-typescript-input-26.0.0.tgz", + "integrity": "sha512-8Fo23bQ2yON2VdjIgPvzLx0nqaqjgUb/xIBcYjd0D4U5cWJ7oABLeNRH0krcSrFp9ez5qDPHB2xbkSLXNFaW9w==", + "license": "Apache-2.0", + "dependencies": { + "quicktype-core": "26.0.0", + "typescript": "5.9.3", + "typescript-json-schema": "0.67.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/stream-chain": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-4.2.5.tgz", + "integrity": "sha512-Wtyq3bNE3ggLR0v2vftqvuhltym3WbZAkZpfIrkr5F/6vpeUmWmwTgXa16zD87gpahwJ/Qulq3zVfUlgIc0J2A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/uhop" + } + }, + "node_modules/stream-json": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-3.5.0.tgz", + "integrity": "sha512-dobB7zipGW8o11PvdRljQSWuyMxifADLvoHeA4elwNWOTbZo6+BlNa+P6aCq7Y9jRiWTy2Ucu2xSv0Y2/T+/kQ==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^4.2.5" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/uhop" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string-to-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", + "integrity": "sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg==", + "license": "MIT", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/string-to-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.3.tgz", + "integrity": "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-json-schema": { + "version": "0.67.4", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.67.4.tgz", + "integrity": "sha512-BhDCVfwGtPKKt9JOBvh6ocmSbEk7ftx7dpqqIpvGNrjzYcUKm8pnYwKSFfNJwqcp/qNTfZr9sKtVyTxx4V9iRA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/json-schema": "^7.0.15", + "@types/node": "^24.10.2", + "glob": "^13.0.6", + "path-equal": "^1.2.5", + "safe-stable-stringify": "^2.5.0", + "ts-node": "^10.9.2", + "typescript": "~5.9.3", + "vm2": "^3.11.3", + "yargs": "^18.0.0" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/typescript-json-schema/node_modules/@types/node": { + "version": "24.13.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.6.tgz", + "integrity": "sha512-SGrw/h3KPFshy3OE6ZL53LMBG5vGQQ8/gIpiqz/kRZhPJ7HgwCEs8LBuNtWLa8dvGZVpSF7+Bf+c11HUrCb/yg==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/typescript-json-schema/node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, + "node_modules/vm2": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.12.2.tgz", + "integrity": "sha512-LRHt4xU6eXshlZEcSZVrTehLGxRDjHvjmFPGwEp4xGpZX61QzH6Xm9wK2nU7XAp36V1w2xILAL1LwxVkgD1Ipw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "acorn-walk": "^8.3.4" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/fdc3-context/src/main/npm/package.json b/fdc3-context/src/main/npm/package.json new file mode 100644 index 00000000..306ff003 --- /dev/null +++ b/fdc3-context/src/main/npm/package.json @@ -0,0 +1,12 @@ +{ + "name": "fdc3-context-codegen", + "version": "1.0.0", + "private": true, + "description": "Pinned toolchain for generating Java types from the FDC3 context JSON schemas. Copied into target/npm-work by the Maven build, which then runs 'npm ci' against the committed lockfile.", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-context": "3.0.0-alpha.5", + "@finos/fdc3-schema": "3.0.0-alpha.5", + "quicktype": "26.0.0" + } +} diff --git a/fdc3-context/src/test/java/org/finos/fdc3/context/ContextRoundTripTest.java b/fdc3-context/src/test/java/org/finos/fdc3/context/ContextRoundTripTest.java new file mode 100644 index 00000000..32ab8cfb --- /dev/null +++ b/fdc3-context/src/test/java/org/finos/fdc3/context/ContextRoundTripTest.java @@ -0,0 +1,223 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.context; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.OffsetDateTime; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests that verify round-trip serialization of FDC3 context types. + * + * For each schema file: + * 1. Read the "examples" from the schema + * 2. Parse each example into the appropriate Java class + * 3. Re-serialize to JSON + * 4. Verify the re-serialized JSON matches the original + */ +public class ContextRoundTripTest { + + private static final ObjectMapper mapper = new ObjectMapper(); + private static Path schemasDir; + + @BeforeAll + static void setUp() { + String basePath = System.getProperty("user.dir"); + // Prefer schemas-work, which holds the npm schemas with the overlay applied + schemasDir = Paths.get(basePath, "target", "schemas-work", "context"); + + if (!Files.exists(schemasDir)) { + // Fallback for builds before prepare-schemas ran + schemasDir = Paths.get(basePath, "target", "npm-work", "node_modules", + "@finos", "fdc3-context", "dist", "schemas", "context"); + } + + if (!Files.exists(schemasDir)) { + // Try relative to project root + schemasDir = Paths.get("fdc3-context", "target", "schemas-work", "context"); + } + } + + @TestFactory + Collection testAllContextTypesRoundTrip() throws IOException { + List tests = new ArrayList<>(); + + if (!Files.exists(schemasDir)) { + System.err.println("Schemas directory not found: " + schemasDir); + System.err.println("Run 'mvn generate-sources' first to download the schemas."); + return tests; + } + + try (Stream paths = Files.list(schemasDir)) { + paths.filter(p -> p.toString().endsWith(".schema.json")) + .forEach(schemaPath -> { + String schemaName = schemaPath.getFileName().toString() + .replace(".schema.json", ""); + + try { + JsonNode schema = mapper.readTree(schemaPath.toFile()); + JsonNode examples = schema.get("examples"); + + if (examples != null && examples.isArray()) { + int exampleIndex = 0; + for (JsonNode example : examples) { + final int idx = exampleIndex++; + final String originalJson = mapper.writeValueAsString(example); + + tests.add(DynamicTest.dynamicTest( + schemaName + " - example " + idx, + () -> testRoundTrip(schemaName, originalJson) + )); + } + } + } catch (IOException e) { + tests.add(DynamicTest.dynamicTest( + schemaName + " - FAILED TO READ", + () -> fail("Failed to read schema: " + e.getMessage()) + )); + } + }); + } + + return tests; + } + + private void testRoundTrip(String schemaName, String originalJson) throws Exception { + // Get the type from the JSON + JsonNode node = mapper.readTree(originalJson); + String type = node.has("type") ? node.get("type").asText() : null; + + assertNotNull(type, "Example should have a 'type' field"); + + // Every type with schema examples must be registered, otherwise ContextConverter.fromJson + // rejects it as unknown and the type is unreachable through the public dispatch API. + Class clazz = ContextConverter.getClassForType(type); + assertNotNull(clazz, "Context type '" + type + "' (from " + schemaName + + ".schema.json) is not registered in ContextConverter.TYPE_MAP, so it cannot be " + + "deserialized via ContextConverter.fromJson(String)"); + + // Parse the JSON into the Java object + Object parsed = ContextConverter.fromJson(originalJson, clazz); + assertNotNull(parsed, "Should be able to parse " + type); + + // The type-dispatching overload must resolve to the same class without being told it + Object dispatched = ContextConverter.fromJson(originalJson); + assertNotNull(dispatched, "Should be able to parse " + type + " via type dispatch"); + assertEquals(clazz, dispatched.getClass(), + "Type dispatch should select " + clazz.getSimpleName() + " for " + type); + + // Re-serialize to JSON + String reserialized = ContextConverter.toJson(parsed); + assertNotNull(reserialized, "Should be able to serialize " + type); + + // Parse both JSONs and compare (ignore formatting differences) + JsonNode originalNode = mapper.readTree(originalJson); + JsonNode reserializedNode = mapper.readTree(reserialized); + + // Check that all original fields are preserved + // Note: The re-serialized version might have fewer fields if they were null + assertJsonContains(originalNode, reserializedNode, schemaName + " (" + type + ")"); + } + + /** + * Asserts that all non-null fields in the original JSON are present in the reserialized JSON. + */ + private void assertJsonContains(JsonNode original, JsonNode reserialized, String context) { + original.fields().forEachRemaining(entry -> { + String fieldName = entry.getKey(); + JsonNode originalValue = entry.getValue(); + JsonNode reserializedValue = reserialized.get(fieldName); + + if (originalValue != null && !originalValue.isNull()) { + assertNotNull(reserializedValue, + "Field '" + fieldName + "' should be present in reserialized JSON for " + context); + + if (originalValue.isObject()) { + // Recursively check nested objects + assertJsonContains(originalValue, reserializedValue, context + "." + fieldName); + } else if (originalValue.isArray()) { + // Check array contents + assertEquals(originalValue.size(), reserializedValue.size(), + "Array '" + fieldName + "' should have same size for " + context); + } else if (originalValue.isNumber() && reserializedValue.isNumber()) { + // Compare numeric values with tolerance for integer/double differences + assertEquals(originalValue.doubleValue(), reserializedValue.doubleValue(), 0.0001, + "Field '" + fieldName + "' should have same numeric value for " + context); + } else if (originalValue.isTextual() && reserializedValue.isTextual()) { + // Compare string values, with special handling for date-times + String orig = originalValue.asText(); + String reser = reserializedValue.asText(); + if (!orig.equals(reser) && isDateTimeString(orig)) { + // Compare as date-times (handles +00:00 vs Z, .000Z vs Z, etc.) + assertTrue(dateTimesEqual(orig, reser), + "DateTime field '" + fieldName + "' should represent same instant for " + context + + " (original: " + orig + ", reserialized: " + reser + ")"); + } else { + assertEquals(orig, reser, + "Field '" + fieldName + "' should have same value for " + context); + } + } else { + // Compare primitive values + assertEquals(originalValue, reserializedValue, + "Field '" + fieldName + "' should have same value for " + context); + } + } + }); + } + + /** + * Check if a string looks like an ISO 8601 date-time. + */ + private boolean isDateTimeString(String s) { + return s != null && s.length() > 10 && s.contains("T") && + (s.endsWith("Z") || s.contains("+") || s.contains("-")); + } + + /** + * Compare two date-time strings, considering different representations of the same instant. + */ + private boolean dateTimesEqual(String dt1, String dt2) { + try { + // Normalize: remove trailing S if present (malformed data in some examples) + String s1 = dt1.replaceAll("S$", ""); + String s2 = dt2.replaceAll("S$", ""); + + OffsetDateTime odt1 = OffsetDateTime.parse(s1); + OffsetDateTime odt2 = OffsetDateTime.parse(s2); + return odt1.toInstant().equals(odt2.toInstant()); + } catch (DateTimeParseException e) { + // If we can't parse as date-time, fall back to string comparison + return dt1.equals(dt2); + } + } +} + diff --git a/fdc3-example-app/README.md b/fdc3-example-app/README.md new file mode 100644 index 00000000..18735c77 --- /dev/null +++ b/fdc3-example-app/README.md @@ -0,0 +1,221 @@ +# FDC3 Example App + +A simple Java Swing application demonstrating FDC3 Desktop Agent connectivity via WebSocket. + +## Features + +- Connects to a Desktop Agent when launched with WSCP credentials, via protocol URL, or on user request +- Supports launch via the `fdc3-java-app://` custom protocol handler (from FDC3-Sail or other DAs) +- Displays available user channels and allows joining/leaving channels +- Shows a log of context broadcasts received on the current channel +- Supports adding and removing context listeners on the user channel + +## Prerequisites + +- Java 17 or higher +- A running FDC3 Desktop Agent (e.g., FDC3-Sail) + +## Building + +From the `fdc3-java-api` root directory: + +```bash +mvn clean package -pl fdc3-example-app -am +``` + +This will create an executable JAR with all dependencies at: +`fdc3-example-app/target/fdc3-example-app-1.0.0-SNAPSHOT.jar` + +## Running + +The application accepts WSCP connection parameters from (in priority order): + +1. **Protocol handler launch URL** — `fdc3-java-app://launch?webSocketUrl=...&sharedSecret=...` +2. **System properties / environment variables** +3. **Connect button** in the UI (manual entry) + +On macOS, protocol URLs are delivered via `Desktop.setOpenURIHandler`, not as `main()` arguments. + +| Property / Variable | Description | +| ------------------------- | -------------------------------------------------------- | +| `FDC3_WEBSOCKET_URL` | WebSocket URL (e.g. `ws://localhost:8090/fdc3/ws`) | +| `FDC3_CONNECTION_SECRET` | Per-instance shared secret from the Sail pairing UI | + +### Manual launch + +```bash +java -DFDC3_WEBSOCKET_URL=ws://localhost:8090/fdc3/ws \ + -DFDC3_CONNECTION_SECRET=your-pairing-secret-from-sail \ + -jar fdc3-example-app/target/fdc3-example-app-1.0.0-SNAPSHOT.jar +``` + +### Using with FDC3-Sail + +**Option A — Open On Desktop (recommended)** + +1. Register the `fdc3-java-app://` protocol handler (see below) +2. Start FDC3-Sail and open **Start Application** +3. Select **FDC3 Java Example App** +4. Click **Open On Desktop** — Sail mints a pairing secret and launches the app via the protocol handler + +**Option B — Manual credentials** + +1. Open the Sail app directory and select the native app +2. Copy the **WebSocket URL** and **shared secret** from the pairing credentials panel +3. Pass them via system properties or click **Connect** in the app +4. Use **Reconnect** after disconnect to resume the same instance with the same secret + +## Protocol handler setup + +Sail launches native apps using URLs of the form: + +``` +fdc3-java-app://launch?webSocketUrl=>&sharedSecret= +``` + +The example app parses these in `ProtocolLaunchParams`. Delivery differs by platform: + +| Platform | How the URL arrives | +| -------- | ------------------- | +| **macOS** | `Desktop.setOpenURIHandler` (requires a jpackage-built `.app`) | +| **Windows** | Command-line argument to the registered handler | + +Helper scripts are in `fdc3-example-app/scripts/`. + +### macOS + +macOS requires a proper **app bundle** to register a custom URL scheme. Use **jpackage** (included with JDK 14+) — do **not** use the old manual `launch.sh` wrapper, which prevents Java from receiving OpenURL events ([JDK-8360120](https://bugs.openjdk.org/browse/JDK-8360120)). + +**Build the app bundle** (macOS only): + +```bash +mvn clean package -pl fdc3-example-app -am -Pmacos-app +``` + +Or run the script directly after `mvn package`: + +```bash +chmod +x fdc3-example-app/scripts/macos/build-app.sh +fdc3-example-app/scripts/macos/build-app.sh +``` + +Output: `fdc3-example-app/target/jpackage-staging/FDC3 Java Example.app` + +**Install and register** (copies to `~/Applications`, clears quarantine, and launches): + +```bash +chmod +x fdc3-example-app/scripts/macos/install-app.sh +fdc3-example-app/scripts/macos/install-app.sh +``` + +Or manually: + +```bash +APP="fdc3-example-app/target/jpackage-staging/FDC3 Java Example.app" +mkdir -p ~/Applications +cp -R "$APP" ~/Applications/ +open "$APP" +``` + +**Test from Terminal:** + +```bash +open "fdc3-java-app://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=test-secret" +``` + +Check the in-app **Context Log** for `Received open URI:` and `Using WSCP connection config from desktop open URI`. + +**Dock icon bounces but no window appears:** this was caused by `-XstartOnFirstThread` in the jpackage build (that flag is for SWT, not Swing — it prevents the AWT event loop from running). Rebuild with a current `-Pmacos-app` build; `build-app.sh` no longer passes that flag. + +**If the app won't start**, diagnose in this order: + +1. **Run the launcher from Terminal** (shows Java errors on stderr): + + ```bash + APP="fdc3-example-app/target/jpackage-staging/FDC3 Java Example.app" + "$APP/Contents/MacOS/FDC3 Java Example" + ``` + +2. **Double-click blocked (unsigned dev build):** use `install-app.sh`, or right-click → Open once. + +3. **Check the code signature:** + + ```bash + codesign --verify --deep --strict --verbose=2 "$APP" + ``` + + Rebuild with `-Pmacos-app` if verification fails. + +4. **Crash logs:** open **Console.app** → Crash Reports, or: + + ```bash + ls ~/Library/Logs/DiagnosticReports/*FDC3* + log stream --predicate 'process == "FDC3 Java Example"' --level debug + ``` + +**After rebuilding:** quit any running copy (`Cmd+Q`), rebuild with `-Pmacos-app`, and re-copy to `~/Applications` if you installed it there. The jpackage bundle always embeds the latest JAR from `target/`. + +To test without the protocol handler: + +```bash +java -jar fdc3-example-app/target/fdc3-example-app-1.0.0-SNAPSHOT.jar \ + 'fdc3-java-app://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=test-secret' +``` + +### Windows + +1. Build the JAR (see above). +2. Register the protocol handler for your user account. + +**Using PowerShell (recommended):** + +```powershell +cd fdc3-example-app\scripts\windows +.\register-protocol.ps1 -JarPath "C:\full\path\to\fdc3-example-app-1.0.0-SNAPSHOT.jar" +``` + +**Using a .reg file:** + +1. Edit `scripts/windows/register-protocol.reg` and replace the placeholder paths to `java.exe` and the JAR. +2. Double-click the file or run `reg import register-protocol.reg`. + +3. Test from Command Prompt: + +```cmd +start "" "fdc3-java-app://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=test-secret" +``` + +Registration is per-user (`HKCU`) when using the PowerShell script, or machine-wide when using `HKEY_CLASSES_ROOT` in the `.reg` file. + +## UI Overview + +### Status Bar + +Shows the connection status to the Desktop Agent. + +### User Channel + +- **Current Channel**: Dropdown to select which user channel to join +- **Leave Channel**: Button to leave the current channel + +### Context Log + +Displays timestamped log entries for: + +- Connection events +- Channel join/leave events +- Context messages received on the current channel + +### Context Listener + +- **Add Listener**: Adds a context listener for all context types on the user channel +- **Remove Listener**: Removes the active context listener + +## Example Usage + +1. Register the protocol handler and start FDC3-Sail, or launch manually with credentials +2. Once connected, select a user channel from the dropdown +3. Click "Add Listener" to start receiving context broadcasts +4. Context received from other apps on the same channel will appear in the log +5. Use "Remove Listener" to stop receiving context +6. Use "Leave Channel" to leave the current channel diff --git a/fdc3-example-app/dependency-reduced-pom.xml b/fdc3-example-app/dependency-reduced-pom.xml new file mode 100644 index 00000000..12d6b3d4 --- /dev/null +++ b/fdc3-example-app/dependency-reduced-pom.xml @@ -0,0 +1,89 @@ + + + + fdc3-parent + org.finos.fdc3 + 1.0.0-SNAPSHOT + + 4.0.0 + fdc3-example-app + FDC3 Example App + Example Java Swing application demonstrating FDC3 Desktop Agent connectivity + + + + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.release} + + + + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + org.finos.fdc3.example.ExampleApp + + ${project.version} + ${maven.build.timestamp} + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + + macos-app + + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + + jpackage-macos-app + package + + exec + + + bash + + ${project.basedir}/scripts/macos/build-app.sh + ${project.version} + + + + + + + + + + + yyyy-MM-dd HH:mm:ss + + diff --git a/fdc3-example-app/pom.xml b/fdc3-example-app/pom.xml new file mode 100644 index 00000000..100f2029 --- /dev/null +++ b/fdc3-example-app/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-example-app + FDC3 Example App + Example Java Swing application demonstrating FDC3 Desktop Agent connectivity + + + yyyy-MM-dd HH:mm:ss + + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + + + org.finos.fdc3 + fdc3-get-agent + ${project.version} + + + + + org.finos.fdc3 + fdc3-schema + ${project.version} + + + + + org.slf4j + slf4j-simple + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.release} + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + org.finos.fdc3.example.ExampleApp + + ${project.version} + ${maven.build.timestamp} + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + + + + macos-app + + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + + jpackage-macos-app + package + + exec + + + bash + + ${project.basedir}/scripts/macos/build-app.sh + ${project.version} + + + + + + + + + + diff --git a/fdc3-example-app/scripts/macos/Info.plist b/fdc3-example-app/scripts/macos/Info.plist new file mode 100644 index 00000000..37970866 --- /dev/null +++ b/fdc3-example-app/scripts/macos/Info.plist @@ -0,0 +1,51 @@ + + + + + + LSMinimumSystemVersion + 10.11 + CFBundleDevelopmentRegion + English + CFBundleAllowMixedLocalizations + + CFBundleExecutable + FDC3 Java Example + CFBundleIconFile + FDC3 Java Example.icns + CFBundleIdentifier + org.finos.fdc3.example + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FDC3 Java Example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + LSApplicationCategoryType + public.app-category.developer-tools + CFBundleVersion + 1.0.0 + NSHumanReadableCopyright + Copyright (C) FINOS + NSHighResolutionCapable + + CFBundleURLTypes + + + CFBundleURLName + FDC3 Java App Launch + CFBundleURLSchemes + + fdc3-java-app + + + + + diff --git a/fdc3-example-app/scripts/macos/build-app.sh b/fdc3-example-app/scripts/macos/build-app.sh new file mode 100755 index 00000000..ffe00219 --- /dev/null +++ b/fdc3-example-app/scripts/macos/build-app.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Builds a macOS .app bundle with jpackage and registers the fdc3-java-app:// URL scheme. +# +# Usage (from repo root or fdc3-example-app): +# fdc3-example-app/scripts/macos/build-app.sh [app-version] +# +# Requires: JDK with jpackage (14+), macOS, a built shaded JAR in target/ + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODULE_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +APP_NAME="FDC3 Java Example" +MAIN_JAR="fdc3-example-app-1.0.0-SNAPSHOT.jar" +MAIN_CLASS="org.finos.fdc3.example.ExampleApp" +BUNDLE_ID="org.finos.fdc3.example" +URL_SCHEME="fdc3-java-app" +RESOURCE_DIR="$SCRIPT_DIR/jpackage-resources" + +APP_VERSION="${1:-1.0.0}" +APP_VERSION="${APP_VERSION/-SNAPSHOT/}" + +JAR_PATH="$MODULE_DIR/target/$MAIN_JAR" +INPUT_DIR="$MODULE_DIR/target/jpackage-input" +OUTPUT_DIR="$MODULE_DIR/target/jpackage-staging" +APP_BUNDLE="$OUTPUT_DIR/$APP_NAME.app" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS app bundles must be built on macOS" >&2 + exit 1 +fi + +if [[ ! -f "$JAR_PATH" ]]; then + echo "error: JAR not found at $JAR_PATH — run: mvn package -pl fdc3-example-app -am" >&2 + exit 1 +fi + +if ! command -v jpackage >/dev/null 2>&1; then + echo "error: jpackage not found on PATH (install a JDK that includes jpackage)" >&2 + exit 1 +fi + +echo "Building $APP_NAME.app (version $APP_VERSION)..." +rm -rf "$APP_BUNDLE" +mkdir -p "$INPUT_DIR" +cp "$JAR_PATH" "$INPUT_DIR/" + +jpackage \ + --type app-image \ + --name "$APP_NAME" \ + --input "$INPUT_DIR" \ + --main-jar "$MAIN_JAR" \ + --main-class "$MAIN_CLASS" \ + --app-version "$APP_VERSION" \ + --mac-package-identifier "$BUNDLE_ID" \ + --resource-dir "$RESOURCE_DIR" \ + --dest "$OUTPUT_DIR" + +if ! codesign --verify --deep --strict --verbose=2 "$APP_BUNDLE" >/dev/null 2>&1; then + echo "error: jpackage app bundle signature verification failed" >&2 + exit 1 +fi + +echo "" +echo "Built: $APP_BUNDLE" +echo "" +echo "Install and launch (recommended — clears Gatekeeper quarantine on copy):" +echo " $SCRIPT_DIR/install-app.sh" +echo "" +echo "Or manually:" +echo " open \"$APP_BUNDLE\"" +echo " open \"${URL_SCHEME}://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=test-secret\"" +echo "" +echo "If double-click in Finder does nothing, the app is unsigned — use install-app.sh" +echo "or right-click → Open once, then double-click will work." diff --git a/fdc3-example-app/scripts/macos/install-app.sh b/fdc3-example-app/scripts/macos/install-app.sh new file mode 100755 index 00000000..089fc8e7 --- /dev/null +++ b/fdc3-example-app/scripts/macos/install-app.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Installs the jpackage-built .app to ~/Applications and launches it. +# +# Usage: +# fdc3-example-app/scripts/macos/install-app.sh +# +# Run build-app.sh (or mvn package -Pmacos-app) first. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODULE_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +APP_NAME="FDC3 Java Example" +SOURCE_APP="$MODULE_DIR/target/jpackage-staging/$APP_NAME.app" +DEST_DIR="${HOME}/Applications" +DEST_APP="$DEST_DIR/$APP_NAME.app" + +if [[ ! -d "$SOURCE_APP" ]]; then + echo "error: $SOURCE_APP not found — run: mvn package -pl fdc3-example-app -am -Pmacos-app" >&2 + exit 1 +fi + +echo "Quitting any running copy..." +pkill -x "$APP_NAME" 2>/dev/null || true +sleep 1 + +mkdir -p "$DEST_DIR" +echo "Installing to $DEST_APP..." +rm -rf "$DEST_APP" +ditto "$SOURCE_APP" "$DEST_APP" + +# Remove quarantine/Gatekeeper flags that block double-click from Finder. +xattr -cr "$DEST_APP" + +echo "Launching..." +open "$DEST_APP" + +echo "" +echo "Installed and launched. Double-click from ~/Applications should work now." +echo "First time only: if macOS still blocks it, open System Settings →" +echo "Privacy & Security → Open Anyway, or right-click the app → Open." diff --git a/fdc3-example-app/scripts/macos/jpackage-resources/Info.plist b/fdc3-example-app/scripts/macos/jpackage-resources/Info.plist new file mode 100644 index 00000000..a64addf5 --- /dev/null +++ b/fdc3-example-app/scripts/macos/jpackage-resources/Info.plist @@ -0,0 +1,47 @@ + + + + + LSMinimumSystemVersion + 10.11 + CFBundleDevelopmentRegion + English + CFBundleAllowMixedLocalizations + + CFBundleExecutable + FDC3 Java Example + CFBundleIconFile + FDC3 Java Example.icns + CFBundleIdentifier + org.finos.fdc3.example + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FDC3 Java Example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + LSApplicationCategoryType + public.app-category.developer-tools + CFBundleVersion + 1.0.0 + NSHumanReadableCopyright + Copyright (C) FINOS + NSHighResolutionCapable + + CFBundleURLTypes + + + CFBundleURLName + FDC3 Java App Launch + CFBundleURLSchemes + + fdc3-java-app + + + + + diff --git a/fdc3-example-app/scripts/macos/launch.sh b/fdc3-example-app/scripts/macos/launch.sh new file mode 100644 index 00000000..9cb6ec84 --- /dev/null +++ b/fdc3-example-app/scripts/macos/launch.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# DEPRECATED: use jpackage instead (see README and scripts/macos/build-app.sh). +# +# A shell-script CFBundleExecutable prevents Java from receiving macOS OpenURL +# events (JDK-8360120). The jpackage-built .app uses a native launcher that +# works with Desktop.setOpenURIHandler(). + +echo "error: use scripts/macos/build-app.sh to build the macOS app bundle" >&2 +exit 1 diff --git a/fdc3-example-app/scripts/windows/register-protocol.ps1 b/fdc3-example-app/scripts/windows/register-protocol.ps1 new file mode 100644 index 00000000..984ab381 --- /dev/null +++ b/fdc3-example-app/scripts/windows/register-protocol.ps1 @@ -0,0 +1,34 @@ +# Registers the fdc3-java-app:// protocol handler on Windows. +# Usage: +# .\register-protocol.ps1 -JarPath "C:\path\to\fdc3-example-app.jar" + +param( + [Parameter(Mandatory = $true)] + [string]$JarPath, + + [string]$JavaPath = (Get-Command java -ErrorAction SilentlyContinue).Source +) + +if (-not $JavaPath) { + throw "java.exe not found on PATH. Pass -JavaPath explicitly." +} + +if (-not (Test-Path $JarPath)) { + throw "JAR not found: $JarPath" +} + +$rootKey = "HKCU:\Software\Classes\fdc3-java-app" +New-Item -Path $rootKey -Force | Out-Null +Set-ItemProperty -Path $rootKey -Name "(Default)" -Value "URL:FDC3 Java App Protocol" +New-ItemProperty -Path $rootKey -Name "URL Protocol" -Value "" -PropertyType String -Force | Out-Null + +$iconKey = Join-Path $rootKey "DefaultIcon" +New-Item -Path $iconKey -Force | Out-Null +Set-ItemProperty -Path $iconKey -Name "(Default)" -Value "$JavaPath,0" + +$commandKey = Join-Path $rootKey "shell\open\command" +New-Item -Path $commandKey -Force | Out-Null +$command = "`"$JavaPath`" -jar `"$JarPath`" `"%1`"" +Set-ItemProperty -Path $commandKey -Name "(Default)" -Value $command + +Write-Host "Registered fdc3-java-app:// -> $JarPath" diff --git a/fdc3-example-app/scripts/windows/register-protocol.reg b/fdc3-example-app/scripts/windows/register-protocol.reg new file mode 100644 index 00000000..395f14e7 --- /dev/null +++ b/fdc3-example-app/scripts/windows/register-protocol.reg @@ -0,0 +1,21 @@ +Windows Registry Editor Version 5.00 + +; Register the fdc3-java-app:// protocol handler for the FDC3 Java Example. +; Before importing: +; 1. Replace C:\\path\\to\\java.exe with your java.exe path +; 2. Replace C:\\path\\to\\fdc3-example-app.jar with your JAR path +; 3. Double-click this file or run: reg import register-protocol.reg + +[HKEY_CLASSES_ROOT\fdc3-java-app] +@="URL:FDC3 Java App Protocol" +"URL Protocol"="" + +[HKEY_CLASSES_ROOT\fdc3-java-app\DefaultIcon] +@="C:\\path\\to\\java.exe,0" + +[HKEY_CLASSES_ROOT\fdc3-java-app\shell] + +[HKEY_CLASSES_ROOT\fdc3-java-app\shell\open] + +[HKEY_CLASSES_ROOT\fdc3-java-app\shell\open\command] +@="\"C:\\path\\to\\java.exe\" -jar \"C:\\path\\to\\fdc3-example-app.jar\" \"%1\"" diff --git a/fdc3-example-app/src/main/java/org/finos/fdc3/example/ExampleApp.java b/fdc3-example-app/src/main/java/org/finos/fdc3/example/ExampleApp.java new file mode 100644 index 00000000..7e0ed693 --- /dev/null +++ b/fdc3-example-app/src/main/java/org/finos/fdc3/example/ExampleApp.java @@ -0,0 +1,1000 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.example; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.getagent.GetAgent; +import org.finos.fdc3.getagent.GetAgentParams; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.border.TitledBorder; +import java.awt.*; +import java.awt.GridLayout; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Example Java Swing application demonstrating FDC3 Desktop Agent connectivity. + *

+ * This application: + *

    + *
  • Connects to a Desktop Agent via WebSocket when launched with credentials or on user request
  • + *
  • Displays the current user channel and allows changing channels
  • + *
  • Shows a log of context broadcasts received on the current channel
  • + *
  • Supports adding and removing context listeners
  • + *
+ *

+ * Required system properties or environment variables: + *

    + *
  • {@code FDC3_WEBSOCKET_URL} - WebSocket URL (e.g. ws://host/fdc3/ws)
  • + *
  • {@code FDC3_CONNECTION_SECRET} - Per-instance shared secret from Sail pairing UI
  • + *
+ */ +public class ExampleApp extends JFrame { + + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); + /** macOS delivers custom protocol URLs via Desktop OpenURIHandler, not main() args. */ + private static final AtomicReference pendingOpenUri = new AtomicReference<>(); + private static volatile ExampleApp activeInstance; + + private DesktopAgent agent; + private Listener contextListener; + private List userChannels; + private Channel currentChannel; + + // UI Components + private JComboBox channelComboBox; + private JTextArea logArea; + private JButton addListenerButton; + private JButton removeListenerButton; + private JLabel statusLabel; + private JLabel listenerStatusLabel; + + // Broadcast buttons + private JButton broadcastInstrumentButton; + private JButton broadcastTeslaButton; + private JButton broadcastCurrencyButton; + private JButton broadcastContactButton; + + private String websocketUrl; + private String sharedSecret; + + private final String[] launchArgs; + + // Stored connection info for reconnection + private String lastInstanceId; + + // Connection buttons + private JButton connectButton; + private JButton disconnectButton; + private JButton reconnectButton; + + public ExampleApp(String[] launchArgs) { + super("FDC3 Example App (" + buildLabel() + ")"); + this.launchArgs = launchArgs != null ? launchArgs : new String[0]; + initUI(); + + SwingUtilities.invokeLater(this::initializeConnection); + } + + /** + * Connect automatically when launch args, a pending protocol URL, or environment + * variables supply WSCP credentials; otherwise wait for Connect or OpenURI. + */ + private void initializeConnection() { + logLaunchArguments(); + + if (tryConnectFromLaunchArgs()) { + return; + } + if (tryConnectFromPendingOpenUri()) { + return; + } + if (tryConnectFromEnvironment()) { + return; + } + showAwaitingConnection(); + } + + private boolean tryConnectFromLaunchArgs() { + for (String arg : launchArgs) { + if (arg != null + && arg.regionMatches(true, 0, ProtocolLaunchParams.SCHEME + "://", 0, + ProtocolLaunchParams.SCHEME.length() + 3)) { + log("Protocol launch URL: " + ProtocolLaunchParams.redactLaunchUri(arg)); + } + } + + Optional protocolLaunch = ProtocolLaunchParams.fromArgs(launchArgs); + if (protocolLaunch.isPresent()) { + applyProtocolLaunchParams(protocolLaunch.get(), "command-line launch URL"); + return true; + } + + if (launchArgs.length > 0) { + log("No WSCP parameters parsed from launch arguments"); + } + return false; + } + + private boolean tryConnectFromPendingOpenUri() { + String uri = pendingOpenUri.getAndSet(null); + if (uri == null) { + return false; + } + return applyProtocolLaunchUri(uri, "desktop open URI"); + } + + private boolean tryConnectFromEnvironment() { + websocketUrl = envOrProperty("FDC3_WEBSOCKET_URL"); + sharedSecret = envOrProperty("FDC3_CONNECTION_SECRET"); + + if (websocketUrl == null || sharedSecret == null) { + return false; + } + log("Using WSCP connection config from environment"); + connectToAgent(); + return true; + } + + private void showAwaitingConnection() { + statusLabel.setText("Not Connected"); + statusLabel.setForeground(Color.GRAY); + connectButton.setEnabled(true); + if (supportsOpenUriHandler()) { + log("No WSCP credentials at startup. Click Connect, or launch from Sail to connect via protocol URL."); + } else { + log("No WSCP credentials at startup. Click Connect to enter WebSocket URL and shared secret."); + } + } + + private static boolean supportsOpenUriHandler() { + if (!Desktop.isDesktopSupported()) { + return false; + } + return Desktop.getDesktop().isSupported(Desktop.Action.APP_OPEN_URI); + } + + private static void registerOpenUriHandler() { + if (!supportsOpenUriHandler()) { + return; + } + Desktop.getDesktop().setOpenURIHandler(event -> { + String uri = event.getURI().toString(); + pendingOpenUri.set(uri); + ExampleApp instance = activeInstance; + if (instance != null) { + // This callback does not run on the EDT, so all Swing access, including the + // log pane write, has to be dispatched. + SwingUtilities.invokeLater(() -> { + instance.log("Received open URI: " + ProtocolLaunchParams.redactLaunchUri(uri)); + instance.handleOpenUri(uri); + }); + } + }); + } + + private void handleOpenUri(String uri) { + pendingOpenUri.compareAndSet(uri, null); + applyProtocolLaunchUri(uri, "desktop open URI"); + } + + private boolean applyProtocolLaunchUri(String uri, String source) { + Optional protocolLaunch = ProtocolLaunchParams.parseLaunchUri(uri); + if (protocolLaunch.isEmpty()) { + log("No WSCP parameters parsed from " + source + ": " + + ProtocolLaunchParams.redactLaunchUri(uri)); + return false; + } + applyProtocolLaunchParams(protocolLaunch.get(), source); + return true; + } + + private void applyProtocolLaunchParams(ProtocolLaunchParams params, String source) { + websocketUrl = params.getWebSocketUrl(); + sharedSecret = params.getSharedSecret(); + log("Parsed WSCP webSocketUrl: " + websocketUrl); + log("Using WSCP connection config from " + source); + if (agent != null) { + disconnect(); + } + connectToAgent(); + } + + private void logLaunchArguments() { + log("Build: " + buildLabel()); + log("URI Handler: " + supportsOpenUriHandler()); + log("Running from: " + codeLocation()); + if (launchArgs.length == 0) { + log("Started with no launch arguments"); + return; + } + log("Launch arguments (" + launchArgs.length + "):"); + for (int i = 0; i < launchArgs.length; i++) { + log(" [" + i + "] " + ProtocolLaunchParams.redactLaunchUri(launchArgs[i])); + } + } + + private static String buildLabel() { + Package pkg = ExampleApp.class.getPackage(); + if (pkg != null && pkg.getImplementationVersion() != null) { + return pkg.getImplementationVersion(); + } + return "dev"; + } + + private static String codeLocation() { + try { + if (ExampleApp.class.getProtectionDomain().getCodeSource() != null) { + return ExampleApp.class.getProtectionDomain().getCodeSource().getLocation().toString(); + } + } catch (SecurityException ignored) { + // fall through + } + return "unknown"; + } + + private static String envOrProperty(String name) { + String v = System.getenv(name); + if (v == null || v.isEmpty()) { + v = System.getProperty(name); + } + return (v == null || v.isEmpty()) ? null : v; + } + + private void promptForConnectionConfig() { + String message = "WSCP connection values are required.\n\n" + + "Copy these from the Sail app directory for your native app:\n" + + " • WebSocket URL (e.g. ws://localhost:8090/fdc3/ws)\n" + + " • Shared secret (unique per app instance)\n\n" + + "Enter WebSocket URL:"; + + String url = JOptionPane.showInputDialog(this, message, "WSCP WebSocket URL", + JOptionPane.QUESTION_MESSAGE); + if (url == null || url.trim().isEmpty()) { + showConfigError("No WebSocket URL provided."); + return; + } + websocketUrl = url.trim(); + + String secret = promptForSharedSecret(); + if (secret == null || secret.trim().isEmpty()) { + showConfigError("No shared secret provided."); + return; + } + sharedSecret = secret.trim(); + + log("Using user-provided WSCP connection config"); + connectToAgent(); + } + + /** + * Prompts for the shared secret using a masked field, so it is not echoed on screen and + * does not linger in the dialog's text. + * + * @return the entered secret, or null if the prompt was cancelled + */ + private String promptForSharedSecret() { + JPasswordField secretField = new JPasswordField(32); + int choice = JOptionPane.showConfirmDialog(this, + new Object[] { "Enter shared secret:", secretField }, + "WSCP Shared Secret", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + + if (choice != JOptionPane.OK_OPTION) { + return null; + } + + char[] entered = secretField.getPassword(); + try { + return new String(entered); + } finally { + // Clear the field's copy. The String above cannot be cleared, which is documented + // as a known limitation in the README. + Arrays.fill(entered, '\0'); + } + } + + private void showConfigError(String msg) { + statusLabel.setText("Not Connected"); + statusLabel.setForeground(Color.RED); + connectButton.setEnabled(true); + log(msg); + log("Click Connect, set FDC3_WEBSOCKET_URL and FDC3_CONNECTION_SECRET, or launch from Sail."); + } + + private void initUI() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(650, 600); + setLocationRelativeTo(null); + + // Main panel with padding + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + + // Top panel - Connection status and channel selection + JPanel topPanel = new JPanel(new BorderLayout(10, 5)); + + // Status panel + JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + statusPanel.add(new JLabel("Status:")); + statusLabel = new JLabel("Not Connected"); + statusLabel.setForeground(Color.GRAY); + statusPanel.add(statusLabel); + + connectButton = new JButton("Connect"); + connectButton.setToolTipText("Enter WSCP WebSocket URL and shared secret"); + connectButton.addActionListener(e -> promptForConnectionConfig()); + statusPanel.add(connectButton); + + disconnectButton = new JButton("Disconnect"); + disconnectButton.setEnabled(false); + disconnectButton.addActionListener(e -> disconnect()); + statusPanel.add(disconnectButton); + + reconnectButton = new JButton("Reconnect"); + reconnectButton.setEnabled(false); + reconnectButton.setToolTipText("Reconnect using the same shared secret"); + reconnectButton.addActionListener(e -> reconnect()); + statusPanel.add(reconnectButton); + + topPanel.add(statusPanel, BorderLayout.NORTH); + + // Channel selection panel + JPanel channelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + channelPanel.setBorder(new TitledBorder("User Channel")); + channelPanel.add(new JLabel("Current Channel:")); + channelComboBox = new JComboBox<>(); + channelComboBox.setPreferredSize(new Dimension(200, 25)); + channelComboBox.setEnabled(false); + channelComboBox.addActionListener(e -> onChannelSelected()); + channelPanel.add(channelComboBox); + + JButton leaveButton = new JButton("Leave Channel"); + leaveButton.addActionListener(e -> leaveChannel()); + channelPanel.add(leaveButton); + + topPanel.add(channelPanel, BorderLayout.CENTER); + + mainPanel.add(topPanel, BorderLayout.NORTH); + + // Center panel - Log area + JPanel logPanel = new JPanel(new BorderLayout()); + logPanel.setBorder(new TitledBorder("Context Log")); + + logArea = new JTextArea(); + logArea.setEditable(false); + logArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); + JScrollPane scrollPane = new JScrollPane(logArea); + scrollPane.setPreferredSize(new Dimension(550, 250)); + logPanel.add(scrollPane, BorderLayout.CENTER); + + JButton clearButton = new JButton("Clear Log"); + clearButton.addActionListener(e -> logArea.setText("")); + JPanel clearPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + clearPanel.add(clearButton); + logPanel.add(clearPanel, BorderLayout.SOUTH); + + mainPanel.add(logPanel, BorderLayout.CENTER); + + // Bottom panel - contains listener controls and broadcast controls + JPanel bottomPanel = new JPanel(new GridLayout(2, 1, 5, 5)); + + // Listener controls + JPanel listenerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + listenerPanel.setBorder(new TitledBorder("Context Listener")); + + listenerStatusLabel = new JLabel("Listener: Not Active"); + listenerStatusLabel.setForeground(Color.GRAY); + listenerPanel.add(listenerStatusLabel); + + addListenerButton = new JButton("Add Listener"); + addListenerButton.setEnabled(false); + addListenerButton.addActionListener(e -> addContextListener()); + listenerPanel.add(addListenerButton); + + removeListenerButton = new JButton("Remove Listener"); + removeListenerButton.setEnabled(false); + removeListenerButton.addActionListener(e -> removeContextListener()); + listenerPanel.add(removeListenerButton); + + bottomPanel.add(listenerPanel); + + // Broadcast controls + JPanel broadcastPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + broadcastPanel.setBorder(new TitledBorder("Broadcast Context (requires channel)")); + + broadcastInstrumentButton = new JButton("Instrument (MSFT)"); + broadcastInstrumentButton.setEnabled(false); + broadcastInstrumentButton.setToolTipText("Broadcast Microsoft stock instrument context"); + broadcastInstrumentButton.addActionListener(e -> broadcastInstrument()); + broadcastPanel.add(broadcastInstrumentButton); + + broadcastTeslaButton = new JButton("Instrument (TSLA)"); + broadcastTeslaButton.setEnabled(false); + broadcastTeslaButton.setToolTipText("Broadcast Tesla stock instrument context"); + broadcastTeslaButton.addActionListener(e -> broadcastTesla()); + broadcastPanel.add(broadcastTeslaButton); + + broadcastCurrencyButton = new JButton("Currency (USD)"); + broadcastCurrencyButton.setEnabled(false); + broadcastCurrencyButton.setToolTipText("Broadcast US Dollar currency context"); + broadcastCurrencyButton.addActionListener(e -> broadcastCurrency()); + broadcastPanel.add(broadcastCurrencyButton); + + broadcastContactButton = new JButton("Contact (Jane Doe)"); + broadcastContactButton.setEnabled(false); + broadcastContactButton.setToolTipText("Broadcast sample contact context"); + broadcastContactButton.addActionListener(e -> broadcastContact()); + broadcastPanel.add(broadcastContactButton); + + bottomPanel.add(broadcastPanel); + + mainPanel.add(bottomPanel, BorderLayout.SOUTH); + + add(mainPanel); + + // Handle window close - cleanup + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + cleanup(); + } + }); + } + + private void connectToAgent() { + if (websocketUrl == null || sharedSecret == null) { + log("ERROR: WSCP connection config incomplete"); + return; + } + + log("Connecting to Desktop Agent at: " + websocketUrl); + + try { + GetAgentParams params = GetAgentParams.builder() + .timeoutMs(30000) + .webSocketUrl(websocketUrl) + .sharedSecret(sharedSecret) + .build(); + + GetAgent.getAgent(params) + .thenAccept(this::onAgentConnected) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> onConnectionError(error)); + return null; + }); + } catch (Exception e) { + onConnectionError(e); + } + } + + private void onAgentConnected(DesktopAgent agent) { + this.agent = agent; + SwingUtilities.invokeLater(() -> { + statusLabel.setText("Connected"); + statusLabel.setForeground(new Color(0, 128, 0)); + disconnectButton.setEnabled(true); + reconnectButton.setEnabled(false); + log("Successfully connected to Desktop Agent"); + + // Store connection info for potential reconnection + storeConnectionInfo(); + + // Load user channels + loadUserChannels(); + }); + } + + /** + * Store instanceId for display after connect. + */ + private void storeConnectionInfo() { + if (agent == null) return; + + agent.getInfo() + .thenAccept(info -> { + if (info != null && info.getAppMetadata() != null) { + lastInstanceId = info.getAppMetadata().getInstanceId(); + + SwingUtilities.invokeLater(() -> { + if (lastInstanceId != null) { + log("Assigned instanceId: " + lastInstanceId); + } + }); + } + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("Warning: Could not retrieve connection info - " + error.getMessage())); + return null; + }); + } + + private void onConnectionError(Throwable error) { + statusLabel.setText("Connection Failed"); + statusLabel.setForeground(Color.RED); + disconnectButton.setEnabled(false); + // Enable reconnect if we have stored credentials + reconnectButton.setEnabled(sharedSecret != null); + log("ERROR: Failed to connect - " + error.getMessage()); + + // Show error dialog with option to retry + int result = JOptionPane.showOptionDialog(this, + "Failed to connect to Desktop Agent:\n" + error.getMessage() + + "\n\nURL: " + websocketUrl + + "\n\nWould you like to enter a different URL?", + "Connection Error", + JOptionPane.YES_NO_OPTION, + JOptionPane.ERROR_MESSAGE, + null, + new String[]{"Enter New URL", "Close"}, + "Enter New URL"); + + if (result == 0) { + promptForConnectionConfig(); + } + } + + /** + * Disconnect from the Desktop Agent. + */ + private void disconnect() { + if (agent == null) return; + + log("Disconnecting from Desktop Agent..."); + + // Clean up listener + if (contextListener != null) { + try { + contextListener.unsubscribe().toCompletableFuture().join(); + contextListener = null; + } catch (Exception e) { + log("Warning: Error unsubscribing listener - " + e.getMessage()); + } + } + + // Disconnect the agent proxy + if (agent instanceof org.finos.fdc3.proxy.DesktopAgentProxy) { + try { + ((org.finos.fdc3.proxy.DesktopAgentProxy) agent).disconnect().toCompletableFuture().join(); + } catch (Exception e) { + log("Warning: Error during disconnect - " + e.getMessage()); + } + } + + agent = null; + currentChannel = null; + + SwingUtilities.invokeLater(() -> { + statusLabel.setText("Disconnected"); + statusLabel.setForeground(Color.GRAY); + disconnectButton.setEnabled(false); + // Enable reconnect if we have stored credentials + reconnectButton.setEnabled(sharedSecret != null); + channelComboBox.setEnabled(false); + channelComboBox.removeAllItems(); + addListenerButton.setEnabled(false); + removeListenerButton.setEnabled(false); + listenerStatusLabel.setText("Listener: Not Active"); + listenerStatusLabel.setForeground(Color.GRAY); + updateBroadcastButtonsState(); + log("Disconnected from Desktop Agent"); + }); + } + + /** + * Reconnect to the Desktop Agent using the same shared secret. + */ + private void reconnect() { + if (websocketUrl == null || sharedSecret == null) { + log("ERROR: webSocketUrl and sharedSecret required for reconnection"); + return; + } + + log("Reconnecting to Desktop Agent..."); + + statusLabel.setText("Reconnecting..."); + statusLabel.setForeground(Color.ORANGE); + reconnectButton.setEnabled(false); + + try { + GetAgentParams params = GetAgentParams.builder() + .timeoutMs(30000) + .webSocketUrl(websocketUrl) + .sharedSecret(sharedSecret) + .build(); + + GetAgent.getAgent(params) + .thenAccept(this::onAgentConnected) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> onConnectionError(error)); + return null; + }); + } catch (Exception e) { + onConnectionError(e); + } + } + + private void loadUserChannels() { + if (agent == null) return; + + log("Loading user channels..."); + agent.getUserChannels() + .thenAccept(channels -> { + this.userChannels = channels; + SwingUtilities.invokeLater(() -> { + channelComboBox.removeAllItems(); + channelComboBox.addItem(new ChannelItem(null)); // "None" option + for (Channel channel : channels) { + channelComboBox.addItem(new ChannelItem(channel)); + } + channelComboBox.setEnabled(true); + addListenerButton.setEnabled(true); + log("Loaded " + channels.size() + " user channels"); + + // Check current channel + loadCurrentChannel(); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to load channels - " + error.getMessage())); + return null; + }); + } + + private void loadCurrentChannel() { + if (agent == null) return; + + agent.getCurrentChannel() + .thenAccept(optChannel -> { + SwingUtilities.invokeLater(() -> { + if (optChannel.isPresent()) { + currentChannel = optChannel.get(); + // Find and select the channel in the combo box + for (int i = 0; i < channelComboBox.getItemCount(); i++) { + ChannelItem item = channelComboBox.getItemAt(i); + if (item.channel != null && + item.channel.getId().equals(currentChannel.getId())) { + channelComboBox.setSelectedIndex(i); + break; + } + } + log("Current channel: " + currentChannel.getId()); + } else { + currentChannel = null; + channelComboBox.setSelectedIndex(0); + log("Not currently joined to any channel"); + } + updateBroadcastButtonsState(); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to get current channel - " + error.getMessage())); + return null; + }); + } + + private void onChannelSelected() { + if (agent == null || !channelComboBox.isEnabled()) return; + + ChannelItem selected = (ChannelItem) channelComboBox.getSelectedItem(); + if (selected == null) return; + + if (selected.channel == null) { + // "None" selected - leave current channel + if (currentChannel != null) { + leaveChannel(); + } + } else if (currentChannel == null || + !currentChannel.getId().equals(selected.channel.getId())) { + // Join the selected channel + joinChannel(selected.channel); + } + } + + private void joinChannel(Channel channel) { + if (agent == null) return; + + log("Joining channel: " + channel.getId()); + agent.joinUserChannel(channel.getId()) + .thenRun(() -> { + currentChannel = channel; + SwingUtilities.invokeLater(() -> { + log("Joined channel: " + channel.getId()); + updateBroadcastButtonsState(); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> { + log("ERROR: Failed to join channel - " + error.getMessage()); + loadCurrentChannel(); // Refresh to show actual state + }); + return null; + }); + } + + private void leaveChannel() { + if (agent == null) return; + + log("Leaving current channel..."); + agent.leaveCurrentChannel() + .thenRun(() -> { + currentChannel = null; + SwingUtilities.invokeLater(() -> { + channelComboBox.setSelectedIndex(0); + log("Left channel"); + updateBroadcastButtonsState(); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to leave channel - " + error.getMessage())); + return null; + }); + } + + private void addContextListener() { + if (agent == null || contextListener != null) return; + + log("Adding context listener (all types)..."); + agent.addContextListener((String) null, this::onContextReceived) + .thenAccept(listener -> { + this.contextListener = listener; + SwingUtilities.invokeLater(() -> { + listenerStatusLabel.setText("Listener: Active"); + listenerStatusLabel.setForeground(new Color(0, 128, 0)); + addListenerButton.setEnabled(false); + removeListenerButton.setEnabled(true); + log("Context listener added successfully"); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to add listener - " + error.getMessage())); + return null; + }); + } + + private void removeContextListener() { + if (contextListener == null) return; + + log("Removing context listener..."); + contextListener.unsubscribe() + .thenRun(() -> { + contextListener = null; + SwingUtilities.invokeLater(() -> { + listenerStatusLabel.setText("Listener: Not Active"); + listenerStatusLabel.setForeground(Color.GRAY); + addListenerButton.setEnabled(true); + removeListenerButton.setEnabled(false); + log("Context listener removed"); + }); + }) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to remove listener - " + error.getMessage())); + return null; + }); + } + + /** + * Update the enabled state of broadcast buttons based on channel membership. + */ + private void updateBroadcastButtonsState() { + boolean canBroadcast = currentChannel != null && agent != null; + broadcastInstrumentButton.setEnabled(canBroadcast); + broadcastTeslaButton.setEnabled(canBroadcast); + broadcastCurrencyButton.setEnabled(canBroadcast); + broadcastContactButton.setEnabled(canBroadcast); + } + + /** + * Broadcast a sample instrument context (Microsoft stock). + */ + private void broadcastInstrument() { + if (agent == null || currentChannel == null) return; + + Map id = new HashMap<>(); + id.put("ticker", "MSFT"); + id.put("ISIN", "US5949181045"); + + Context instrumentContext = new Context("fdc3.instrument", "Microsoft", id); + + log("Broadcasting instrument context: Microsoft (MSFT)"); + agent.broadcast(instrumentContext) + .thenRun(() -> SwingUtilities.invokeLater(() -> + log("Successfully broadcast instrument context"))) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to broadcast - " + error.getMessage())); + return null; + }); + } + + /** + * Broadcast a sample instrument context (Tesla stock). + */ + private void broadcastTesla() { + if (agent == null || currentChannel == null) return; + + Map id = new HashMap<>(); + id.put("ticker", "TSLA"); + id.put("ISIN", "US88160R1014"); + + Context instrumentContext = new Context("fdc3.instrument", "Tesla", id); + + log("Broadcasting instrument context: Tesla (TSLA)"); + agent.broadcast(instrumentContext) + .thenRun(() -> SwingUtilities.invokeLater(() -> + log("Successfully broadcast instrument context"))) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to broadcast - " + error.getMessage())); + return null; + }); + } + + /** + * Broadcast a sample currency context (US Dollar). + */ + private void broadcastCurrency() { + if (agent == null || currentChannel == null) return; + + Map id = new HashMap<>(); + id.put("CURRENCY_ISOCODE", "USD"); + + Context currencyContext = new Context("fdc3.currency", "US Dollar", id); + + log("Broadcasting currency context: US Dollar (USD)"); + agent.broadcast(currencyContext) + .thenRun(() -> SwingUtilities.invokeLater(() -> + log("Successfully broadcast currency context"))) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to broadcast - " + error.getMessage())); + return null; + }); + } + + /** + * Broadcast a sample contact context (Jane Doe). + */ + private void broadcastContact() { + if (agent == null || currentChannel == null) return; + + Map id = new HashMap<>(); + id.put("email", "jane.doe@mail.com"); + + Context contactContext = new Context("fdc3.contact", "Jane Doe", id); + + log("Broadcasting contact context: Jane Doe"); + agent.broadcast(contactContext) + .thenRun(() -> SwingUtilities.invokeLater(() -> + log("Successfully broadcast contact context"))) + .exceptionally(error -> { + SwingUtilities.invokeLater(() -> + log("ERROR: Failed to broadcast - " + error.getMessage())); + return null; + }); + } + + private void onContextReceived(Context context, ContextMetadata metadata) { + SwingUtilities.invokeLater(() -> { + StringBuilder sb = new StringBuilder(); + sb.append("=== CONTEXT RECEIVED ===\n"); + sb.append("Type: ").append(context.getType()).append("\n"); + + if (metadata != null && metadata.getSource() != null) { + sb.append("Source: ").append(metadata.getSource().getAppId()); + if (metadata.getSource().getInstanceId() != null) { + sb.append(" (").append(metadata.getSource().getInstanceId()).append(")"); + } + sb.append("\n"); + } + + // Log the context details + try { + String contextJson = context.toString(); + sb.append("Data: ").append(contextJson).append("\n"); + } catch (Exception e) { + sb.append("Data: [Error formatting context]\n"); + } + + log(sb.toString()); + }); + } + + private void log(String message) { + String timestamp = LocalDateTime.now().format(TIME_FORMAT); + String logMessage = "[" + timestamp + "] " + message + "\n"; + logArea.append(logMessage); + // Auto-scroll to bottom + logArea.setCaretPosition(logArea.getDocument().getLength()); + } + + private void cleanup() { + if (contextListener != null) { + try { + contextListener.unsubscribe().toCompletableFuture().join(); + } catch (Exception e) { + // Ignore cleanup errors + } + } + } + + /** + * Helper class to display channels in the combo box + */ + private static class ChannelItem { + final Channel channel; + + ChannelItem(Channel channel) { + this.channel = channel; + } + + @Override + public String toString() { + if (channel == null) { + return "(None)"; + } + String name = channel.getId(); + if (channel.getDisplayMetadata() != null && + channel.getDisplayMetadata().getName() != null) { + name = channel.getDisplayMetadata().getName(); + } + return name + " [" + channel.getId() + "]"; + } + } + + public static void main(String[] args) { + String[] launchArgs = args != null ? args : new String[0]; + + // Set look and feel + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + // Use default look and feel + } + + // macOS delivers protocol URLs via Desktop.setOpenURIHandler (requires jpackage .app). + registerOpenUriHandler(); + + // Create and show the application + SwingUtilities.invokeLater(() -> { + ExampleApp app = new ExampleApp(launchArgs); + activeInstance = app; + app.setVisible(true); + }); + } +} diff --git a/fdc3-example-app/src/main/java/org/finos/fdc3/example/ProtocolLaunchParams.java b/fdc3-example-app/src/main/java/org/finos/fdc3/example/ProtocolLaunchParams.java new file mode 100644 index 00000000..ff906f66 --- /dev/null +++ b/fdc3-example-app/src/main/java/org/finos/fdc3/example/ProtocolLaunchParams.java @@ -0,0 +1,170 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.example; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; + +/** + * Parses WSCP launch parameters from a custom protocol handler URL. + *

+ * Example: + * {@code fdc3-java-app://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=...} + */ +public final class ProtocolLaunchParams { + + /** Custom URL scheme registered with the OS for this application. */ + public static final String SCHEME = "fdc3-java-app"; + + /** Matches the {@code sharedSecret} query value, in either encoded or plain form. */ + private static final Pattern SHARED_SECRET_VALUE = + Pattern.compile("(?i)(sharedSecret=)[^&#\\s]*"); + + private final String webSocketUrl; + private final String sharedSecret; + + private ProtocolLaunchParams(String webSocketUrl, String sharedSecret) { + this.webSocketUrl = webSocketUrl; + this.sharedSecret = sharedSecret; + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getSharedSecret() { + return sharedSecret; + } + + /** + * Looks for a protocol launch URL in the process arguments. + * Rejoins arguments when a shell splits the URL at {@code &}. + */ + public static Optional fromArgs(String[] args) { + if (args == null || args.length == 0) { + return Optional.empty(); + } + for (String arg : args) { + Optional parsed = parseLaunchUri(arg); + if (parsed.isPresent()) { + return parsed; + } + } + for (int i = 0; i < args.length; i++) { + if (!isSchemeUrl(args[i])) { + continue; + } + StringBuilder rebuilt = new StringBuilder(args[i].trim()); + for (int j = i + 1; j < args.length; j++) { + String part = args[j]; + if (part == null || part.isBlank()) { + continue; + } + if (isSchemeUrl(part)) { + break; + } + if (!rebuilt.toString().contains("?")) { + rebuilt.append('?'); + } + if (!part.startsWith("&")) { + rebuilt.append('&'); + } + rebuilt.append(part); + } + Optional parsed = parseLaunchUri(rebuilt.toString()); + if (parsed.isPresent()) { + return parsed; + } + } + return Optional.empty(); + } + + /** + * Masks the {@code sharedSecret} query value so that a launch URL can be logged or shown + * on screen. The secret is the WSCP connection credential and must not be disclosed. + * + * @param uri a launch URI, which may be null + * @return the URI with the secret replaced, or null if the input was null + */ + public static String redactLaunchUri(String uri) { + if (uri == null) { + return null; + } + return SHARED_SECRET_VALUE.matcher(uri).replaceAll("$1"); + } + + private static boolean isSchemeUrl(String value) { + return value != null + && value.regionMatches(true, 0, SCHEME + "://", 0, SCHEME.length() + 3); + } + + /** + * Parses a {@code fdc3-java-app://...} launch URI. + */ + public static Optional parseLaunchUri(String uri) { + if (uri == null || uri.isBlank()) { + return Optional.empty(); + } + + String normalized = uri.trim(); + if (!normalized.regionMatches(true, 0, SCHEME + "://", 0, SCHEME.length() + 3)) { + return Optional.empty(); + } + + try { + int queryStart = normalized.indexOf('?'); + String rawQuery = queryStart >= 0 ? normalized.substring(queryStart + 1) : null; + if (rawQuery != null) { + int hash = rawQuery.indexOf('#'); + if (hash >= 0) { + rawQuery = rawQuery.substring(0, hash); + } + } + Map query = parseQuery(rawQuery); + String webSocketUrl = query.get("webSocketUrl"); + String sharedSecret = query.get("sharedSecret"); + if (webSocketUrl == null || webSocketUrl.isBlank() + || sharedSecret == null || sharedSecret.isBlank()) { + return Optional.empty(); + } + return Optional.of(new ProtocolLaunchParams(webSocketUrl, sharedSecret)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + private static Map parseQuery(String rawQuery) { + Map params = new HashMap<>(); + if (rawQuery == null || rawQuery.isEmpty()) { + return params; + } + for (String pair : rawQuery.split("&")) { + int separator = pair.indexOf('='); + if (separator <= 0) { + continue; + } + String key = URLDecoder.decode(pair.substring(0, separator), StandardCharsets.UTF_8); + String value = URLDecoder.decode(pair.substring(separator + 1), StandardCharsets.UTF_8); + params.put(key, value); + } + return params; + } +} diff --git a/fdc3-get-agent/pom.xml b/fdc3-get-agent/pom.xml new file mode 100644 index 00000000..bc40c18e --- /dev/null +++ b/fdc3-get-agent/pom.xml @@ -0,0 +1,138 @@ + + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-get-agent + FDC3 Get Agent + Factory for obtaining a DesktopAgent connection via WebSocket + + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + + + org.finos.fdc3 + fdc3-agent-proxy + ${project.version} + + + + + org.finos.fdc3 + fdc3-schema + ${project.version} + + + + + jakarta.websocket + jakarta.websocket-client-api + + + + + org.glassfish.tyrus.bundles + tyrus-standalone-client + + + + + org.glassfish.tyrus + tyrus-server + test + + + org.glassfish.tyrus + tyrus-container-grizzly-server + test + + + + + org.slf4j + slf4j-api + + + + + org.finos + cucumber-testing-steps + test + + + io.cucumber + cucumber-spring + test + + + org.springframework + spring-context + test + + + org.springframework + spring-test + test + + + io.cucumber + cucumber-junit-platform-engine + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-suite + test + + + org.slf4j + slf4j-simple + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.release} + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.2 + + + + cucumber.junit-platform.naming-strategy=long + cucumber.junit-platform.discovery.as-root-engine=false + + + + + + + diff --git a/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgent.java b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgent.java new file mode 100644 index 00000000..ac1b9595 --- /dev/null +++ b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgent.java @@ -0,0 +1,298 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.errors.FDC3ConnectionException; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.ui.Connectable; +import org.finos.fdc3.proxy.DesktopAgentProxy; +import org.finos.fdc3.proxy.apps.DefaultAppSupport; +import org.finos.fdc3.proxy.channels.DefaultChannelSupport; +import org.finos.fdc3.proxy.heartbeat.DefaultHeartbeatSupport; +import org.finos.fdc3.proxy.intents.DefaultIntentSupport; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.schema.ProtocolVersion; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnect; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnectMeta; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnectPayload; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnectType; + +/** + * Factory for obtaining a DesktopAgent connection via WebSocket using WSCP. + */ +public class GetAgent { + + private static final String WSCP_DESKTOP_AGENT_CONNECT = "WSCPDesktopAgentConnect"; + private static final String WSCP_CONNECT_FAILED = "WSCPConnectFailed"; + + private GetAgent() { + } + + public static CompletionStage getAgent(GetAgentParams params) { + Logger.info("Initiating Desktop Agent connection to {}", params.getWebSocketUrl()); + + AppIdentifier tempAppId = new AppIdentifier("pending", null, null); + WebSocketMessaging messaging = new WebSocketMessaging( + params.getWebSocketUrl(), tempAppId, params.getTimeoutMs()); + + return messaging.connect() + .thenCompose(v -> performHandshake(messaging, params)) + .thenApply(validationResult -> createDesktopAgent(messaging, validationResult, params)) + .exceptionally(error -> { + try { + messaging.disconnect(); + } catch (Exception e) { + Logger.error("Error during cleanup: {}", e.getMessage()); + } + + if (error.getCause() instanceof FDC3ConnectionException) { + throw (FDC3ConnectionException) error.getCause(); + } + throw new FDC3ConnectionException("Failed to connect to Desktop Agent", error); + }); + } + + private static CompletionStage performHandshake( + WebSocketMessaging messaging, GetAgentParams params) { + + String connectionAttemptUuid = UUID.randomUUID().toString(); + + WebSocketConnectionProtocolApplicationConnect connectMsg = + new WebSocketConnectionProtocolApplicationConnect(); + connectMsg.setType( + WebSocketConnectionProtocolApplicationConnectType.WSCP_APPLICATION_CONNECT); + + WebSocketConnectionProtocolApplicationConnectMeta meta = + new WebSocketConnectionProtocolApplicationConnectMeta(); + meta.setConnectionAttemptUUID(connectionAttemptUuid); + meta.setTimestamp(OffsetDateTime.now()); + connectMsg.setMeta(meta); + + WebSocketConnectionProtocolApplicationConnectPayload payload = + new WebSocketConnectionProtocolApplicationConnectPayload(); + payload.setProtocolVersion(ProtocolVersion.THE_10); + payload.setSharedSecret(params.getSharedSecret()); + connectMsg.setPayload(payload); + + Map connectMessage = messaging.getConverter().toMap(connectMsg); + + CompletableFuture responseFuture = new CompletableFuture<>(); + + messaging.register(new org.finos.fdc3.proxy.listeners.RegisterableListener() { + private final String id = UUID.randomUUID().toString(); + + @Override + public String getId() { + return id; + } + + @Override + @SuppressWarnings("unchecked") + public boolean filter(Map message) { + String type = (String) message.get("type"); + if (!WSCP_DESKTOP_AGENT_CONNECT.equals(type) + && !WSCP_CONNECT_FAILED.equals(type)) { + return false; + } + + Map msgMeta = (Map) message.get("meta"); + if (msgMeta == null) { + return false; + } + String respConnectionAttemptUuid = (String) msgMeta.get("connectionAttemptUuid"); + return connectionAttemptUuid.equals(respConnectionAttemptUuid); + } + + @Override + @SuppressWarnings("unchecked") + public void action(Map message) { + messaging.unregister(id); + + String type = (String) message.get("type"); + Map responsePayload = (Map) message.get("payload"); + + if (WSCP_CONNECT_FAILED.equals(type)) { + String errorMessage = responsePayload != null + ? (String) responsePayload.get("message") + : "Connection failed"; + responseFuture.completeExceptionally( + new FDC3ConnectionException("Connection failed: " + errorMessage)); + return; + } + + try { + ValidationResult result = new ValidationResult(); + + Map implMeta = + (Map) responsePayload.get("implementationMetadata"); + if (implMeta != null) { + result.implementationMetadata = parseImplementationMetadata(implMeta); + AppMetadata appMetadata = result.implementationMetadata.getAppMetadata(); + if (appMetadata != null) { + result.appId = appMetadata.getAppId(); + result.instanceId = appMetadata.getInstanceId(); + } + } + + if (result.appId == null || result.instanceId == null) { + throw new FDC3ConnectionException( + "WSCPDesktopAgentConnect missing appMetadata appId/instanceId"); + } + + Logger.info("WSCP handshake successful - appId: {}, instanceId: {}", + result.appId, result.instanceId); + responseFuture.complete(result); + } catch (Exception e) { + responseFuture.completeExceptionally( + new FDC3ConnectionException("Failed to parse WSCPDesktopAgentConnect", e)); + } + } + + @Override + public CompletionStage register() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage unsubscribe() { + messaging.unregister(id); + return CompletableFuture.completedFuture(null); + } + }); + + Logger.debug("Sending WSCPApplicationConnect message"); + messaging.post(connectMessage); + + return responseFuture + .orTimeout(params.getTimeoutMs(), TimeUnit.MILLISECONDS) + .exceptionally(error -> { + if (error instanceof TimeoutException + || (error.getCause() != null + && error.getCause() instanceof TimeoutException)) { + throw new FDC3ConnectionException( + "Connection timeout waiting for WSCPDesktopAgentConnect"); + } + if (error instanceof FDC3ConnectionException) { + throw (FDC3ConnectionException) error; + } + throw new FDC3ConnectionException("Handshake failed", error); + }); + } + + @SuppressWarnings("unchecked") + private static ImplementationMetadata parseImplementationMetadata(Map implMeta) { + ImplementationMetadata metadata = new ImplementationMetadata(); + + metadata.setFdc3Version((String) implMeta.get("fdc3Version")); + metadata.setProvider((String) implMeta.get("provider")); + metadata.setProviderVersion((String) implMeta.get("providerVersion")); + + Map appMeta = (Map) implMeta.get("appMetadata"); + if (appMeta != null) { + AppMetadata appMetadata = new AppMetadata(); + appMetadata.setAppId((String) appMeta.get("appId")); + appMetadata.setInstanceId((String) appMeta.get("instanceId")); + appMetadata.setName((String) appMeta.get("name")); + appMetadata.setVersion((String) appMeta.get("version")); + appMetadata.setTitle((String) appMeta.get("title")); + appMetadata.setTooltip((String) appMeta.get("tooltip")); + appMetadata.setDescription((String) appMeta.get("description")); + metadata.setAppMetadata(appMetadata); + } + + Map optFeatures = (Map) implMeta.get("optionalFeatures"); + if (optFeatures != null) { + ImplementationMetadata.OptionalFeatures features = + new ImplementationMetadata.OptionalFeatures(); + if (optFeatures.get("UserChannelMembershipAPIs") != null) { + features.setUserChannelMembershipAPIs( + (Boolean) optFeatures.get("UserChannelMembershipAPIs")); + } + if (optFeatures.get("DesktopAgentBridging") != null) { + features.setDesktopAgentBridging((Boolean) optFeatures.get("DesktopAgentBridging")); + } + metadata.setOptionalFeatures(features); + } + + return metadata; + } + + private static DesktopAgent createDesktopAgent( + WebSocketMessaging messaging, + ValidationResult validationResult, + GetAgentParams params) { + + AppIdentifier appIdentifier = new AppIdentifier( + validationResult.appId, + validationResult.instanceId, + null); + + messaging.setIdentifier(appIdentifier); + + DefaultHeartbeatSupport heartbeatSupport = new DefaultHeartbeatSupport( + messaging, params.getHeartbeatIntervalMs()); + + DefaultChannelSupport channelSupport = new DefaultChannelSupport( + messaging, params.getChannelSelector(), params.getMessageExchangeTimeout()); + + DefaultIntentSupport intentSupport = new DefaultIntentSupport( + messaging, params.getIntentResolver(), + params.getMessageExchangeTimeout(), params.getAppLaunchTimeout()); + + DefaultAppSupport appSupport = new DefaultAppSupport( + messaging, params.getMessageExchangeTimeout(), params.getAppLaunchTimeout()); + + List connectables = new ArrayList<>(); + connectables.add(heartbeatSupport); + + DesktopAgentProxy proxy = new DesktopAgentProxy( + heartbeatSupport, + channelSupport, + intentSupport, + appSupport, + connectables); + + proxy.connect().exceptionally(error -> { + // getAgent() has already resolved by this point, so the only useful thing left is to + // say why the proxy did not finish connecting. + Logger.error("DesktopAgent proxy failed to complete connection setup", error); + return null; + }); + + Logger.info("DesktopAgent proxy created successfully"); + return proxy; + } + + private static class ValidationResult { + String appId; + String instanceId; + ImplementationMetadata implementationMetadata; + } +} diff --git a/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgentParams.java b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgentParams.java new file mode 100644 index 00000000..4775772f --- /dev/null +++ b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/GetAgentParams.java @@ -0,0 +1,266 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Locale; + +import org.finos.fdc3.api.ui.ChannelSelector; +import org.finos.fdc3.api.ui.IntentResolver; +import org.finos.fdc3.getagent.ui.DefaultChannelSelector; +import org.finos.fdc3.getagent.ui.DefaultIntentResolver; +import org.finos.fdc3.proxy.util.Logger; + +/** + * Parameters for obtaining a DesktopAgent connection via WebSocket. + *

+ * Uses the WebSocket Connection Protocol (WSCP) for the initial handshake. + *

+ * The following environment variables / system properties provide defaults: + *

    + *
  • {@code FDC3_WEBSOCKET_URL} — deployment WebSocket endpoint (e.g. ws://host/fdc3/ws)
  • + *
  • {@code FDC3_CONNECTION_SECRET} — pairing secret from the Desktop Agent UI (required)
  • + *
+ * The shared secret implicitly identifies the FDC3 session and app instance. The same secret + * MUST be presented again when reconnecting after interruption. + */ +public class GetAgentParams { + + public static final String PROP_WEBSOCKET_URL = "FDC3_WEBSOCKET_URL"; + public static final String PROP_CONNECTION_SECRET = "FDC3_CONNECTION_SECRET"; + + private final String webSocketUrl; + private final String sharedSecret; + private final ChannelSelector channelSelector; + private final IntentResolver intentResolver; + private final long timeoutMs; + private final long messageExchangeTimeout; + private final long appLaunchTimeout; + private final long heartbeatIntervalMs; + private final boolean allowInsecureTransport; + + private GetAgentParams(Builder builder) { + this.webSocketUrl = builder.webSocketUrl; + this.sharedSecret = builder.sharedSecret; + this.channelSelector = builder.channelSelector; + this.intentResolver = builder.intentResolver; + this.timeoutMs = builder.timeoutMs; + this.messageExchangeTimeout = builder.messageExchangeTimeout; + this.appLaunchTimeout = builder.appLaunchTimeout; + this.heartbeatIntervalMs = builder.heartbeatIntervalMs; + this.allowInsecureTransport = builder.allowInsecureTransport; + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getSharedSecret() { + return sharedSecret; + } + + public ChannelSelector getChannelSelector() { + return channelSelector; + } + + public IntentResolver getIntentResolver() { + return intentResolver; + } + + public long getTimeoutMs() { + return timeoutMs; + } + + public long getMessageExchangeTimeout() { + return messageExchangeTimeout; + } + + public long getAppLaunchTimeout() { + return appLaunchTimeout; + } + + public long getHeartbeatIntervalMs() { + return heartbeatIntervalMs; + } + + /** Whether plaintext {@code ws://} to a non-loopback host was explicitly permitted. */ + public boolean isAllowInsecureTransport() { + return allowInsecureTransport; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String webSocketUrl = firstNonEmpty( + System.getenv(PROP_WEBSOCKET_URL), + System.getProperty(PROP_WEBSOCKET_URL)); + private String sharedSecret = firstNonEmpty( + System.getenv(PROP_CONNECTION_SECRET), + System.getProperty(PROP_CONNECTION_SECRET)); + private ChannelSelector channelSelector = new DefaultChannelSelector(); + private IntentResolver intentResolver = new DefaultIntentResolver(); + private long timeoutMs = 10000; + private long messageExchangeTimeout = 10000; + private long appLaunchTimeout = 30000; + private long heartbeatIntervalMs = 5000; + private boolean allowInsecureTransport = false; + + private static String firstNonEmpty(String a, String b) { + if (a != null && !a.isEmpty()) { + return a; + } + if (b != null && !b.isEmpty()) { + return b; + } + return null; + } + + public Builder webSocketUrl(String webSocketUrl) { + this.webSocketUrl = webSocketUrl; + return this; + } + + public Builder sharedSecret(String sharedSecret) { + this.sharedSecret = sharedSecret; + return this; + } + + public Builder channelSelector(ChannelSelector channelSelector) { + this.channelSelector = channelSelector != null ? channelSelector : new DefaultChannelSelector(); + return this; + } + + public Builder intentResolver(IntentResolver intentResolver) { + this.intentResolver = intentResolver != null ? intentResolver : new DefaultIntentResolver(); + return this; + } + + public Builder timeoutMs(long timeoutMs) { + this.timeoutMs = timeoutMs; + return this; + } + + public Builder messageExchangeTimeout(long messageExchangeTimeout) { + this.messageExchangeTimeout = messageExchangeTimeout; + return this; + } + + public Builder appLaunchTimeout(long appLaunchTimeout) { + this.appLaunchTimeout = appLaunchTimeout; + return this; + } + + public Builder heartbeatIntervalMs(long heartbeatIntervalMs) { + this.heartbeatIntervalMs = heartbeatIntervalMs; + return this; + } + + /** + * Permits a plaintext {@code ws://} URL to a non-loopback host. + *

+ * The shared secret is sent in the first message of the connection, so without TLS it + * is readable by anything on the network path. Loopback URLs are always allowed and do + * not need this flag. + * + * @param allowInsecureTransport true to allow plaintext to a remote host + */ + public Builder allowInsecureTransport(boolean allowInsecureTransport) { + this.allowInsecureTransport = allowInsecureTransport; + return this; + } + + public GetAgentParams build() { + if (webSocketUrl == null || webSocketUrl.isEmpty()) { + throw new IllegalArgumentException("webSocketUrl is required"); + } + if (sharedSecret == null || sharedSecret.isEmpty()) { + throw new IllegalArgumentException("sharedSecret is required"); + } + validateTransport(webSocketUrl, allowInsecureTransport); + return new GetAgentParams(this); + } + } + + /** + * Checks that the WebSocket URL is well formed and that the shared secret will not be sent + * in clear text to a remote host. + *

+ * The WSCP specification does not mandate transport security, so this is a hardening + * decision of this implementation rather than a conformance requirement. + */ + private static void validateTransport(String webSocketUrl, boolean allowInsecureTransport) { + URI uri; + try { + uri = new URI(webSocketUrl); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("webSocketUrl is not a valid URI: " + webSocketUrl, e); + } + + String scheme = uri.getScheme(); + if (scheme == null) { + throw new IllegalArgumentException( + "webSocketUrl must specify a scheme of ws or wss: " + webSocketUrl); + } + + scheme = scheme.toLowerCase(Locale.ROOT); + if ("wss".equals(scheme)) { + return; + } + if (!"ws".equals(scheme)) { + throw new IllegalArgumentException( + "webSocketUrl scheme must be ws or wss, but was " + scheme); + } + + if (isLoopbackHost(uri.getHost())) { + return; + } + + if (!allowInsecureTransport) { + throw new IllegalArgumentException( + "Refusing to send the shared secret in clear text to a remote host. Use a wss:// " + + "URL, or call allowInsecureTransport(true) to accept the risk: " + + webSocketUrl); + } + + Logger.warn("Connecting over plaintext ws:// to {}. The shared secret will be sent " + + "unencrypted and is readable on the network path.", uri.getHost()); + } + + /** + * Whether a host refers to the local machine, in which case plaintext traffic does not + * leave the host. Deliberately a literal comparison: resolving names here would make + * validation depend on DNS. + */ + private static boolean isLoopbackHost(String host) { + if (host == null || host.isEmpty()) { + return false; + } + + String candidate = host.toLowerCase(Locale.ROOT); + if (candidate.startsWith("[") && candidate.endsWith("]")) { + candidate = candidate.substring(1, candidate.length() - 1); + } + + return "localhost".equals(candidate) + || "::1".equals(candidate) + || "0:0:0:0:0:0:0:1".equals(candidate) + || candidate.startsWith("127."); + } +} diff --git a/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/WebSocketMessaging.java b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/WebSocketMessaging.java new file mode 100644 index 00000000..f633cdc5 --- /dev/null +++ b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/WebSocketMessaging.java @@ -0,0 +1,379 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent; + +import java.io.IOException; +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import jakarta.websocket.ClientEndpoint; +import jakarta.websocket.CloseReason; +import jakarta.websocket.ContainerProvider; +import jakarta.websocket.OnClose; +import jakarta.websocket.OnError; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.WebSocketContainer; + +import org.finos.fdc3.api.errors.FDC3ConnectionException; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.proxy.listeners.RegisterableListener; +import org.finos.fdc3.proxy.messaging.AbstractMessaging; +import org.finos.fdc3.proxy.util.Logger; +import org.finos.fdc3.proxy.util.MessageLogging; + +/** + * WebSocket-based implementation of the Messaging interface. + *

+ * This class manages the WebSocket connection to the FDC3 Desktop Agent + * and handles sending/receiving messages. + */ +@ClientEndpoint +public class WebSocketMessaging extends AbstractMessaging { + + /** Applied when no explicit connect timeout is supplied. */ + private static final long DEFAULT_CONNECT_TIMEOUT_MS = 10000; + + private final String webSocketUrl; + private final long connectTimeoutMs; + private final Map listeners = new ConcurrentHashMap<>(); + + // Assigned on the WebSocket container's callback threads and read by callers of post(), + // disconnect() and isConnected(), so both need to be visible across threads. + private volatile Session session; + private volatile CompletableFuture connectionFuture; + private volatile CompletableFuture disconnectFuture; + private volatile boolean connected = false; + + /** Retained so its thread pools can be released on disconnect rather than leaked. */ + private volatile WebSocketContainer container; + + /** Set while {@link #disconnect()} is in progress, to tell a graceful close from a drop. */ + private volatile boolean closeExpected = false; + + /** + * Creates a new WebSocketMessaging instance. + * + * @param webSocketUrl the WebSocket URL to connect to + * @param appIdentifier the application identifier + */ + public WebSocketMessaging(String webSocketUrl, AppIdentifier appIdentifier) { + this(webSocketUrl, appIdentifier, DEFAULT_CONNECT_TIMEOUT_MS); + } + + /** + * Creates a new WebSocketMessaging instance. + * + * @param webSocketUrl the WebSocket URL to connect to + * @param appIdentifier the application identifier + * @param connectTimeoutMs how long to wait for the WebSocket handshake to complete + */ + public WebSocketMessaging(String webSocketUrl, AppIdentifier appIdentifier, long connectTimeoutMs) { + super(appIdentifier); + this.webSocketUrl = webSocketUrl; + this.connectTimeoutMs = connectTimeoutMs; + } + + /** + * Connects to the WebSocket server. + *

+ * The returned stage is bounded by the connect timeout. Without it, a server that accepts + * the TCP connection but never completes the WebSocket upgrade would leave + * {@code getAgent()} waiting indefinitely, since the message-level timeout only starts once + * the connection is open. + * + * @return a CompletionStage that completes when the connection is established + */ + public CompletionStage connect() { + if (connected && session != null && session.isOpen()) { + return CompletableFuture.completedFuture(null); + } + + CompletableFuture pending = new CompletableFuture<>(); + connectionFuture = pending; + + try { + WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer(); + container = webSocketContainer; + webSocketContainer.connectToServer(this, URI.create(webSocketUrl)); + } catch (Exception e) { + pending.completeExceptionally(e); + } + + return pending + .orTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS) + .exceptionally(error -> { + if (error instanceof TimeoutException + || error.getCause() instanceof TimeoutException) { + shutdownContainer(); + throw new FDC3ConnectionException( + "Timed out after " + connectTimeoutMs + + "ms waiting for the WebSocket connection to " + webSocketUrl); + } + if (error instanceof RuntimeException) { + throw (RuntimeException) error; + } + throw new FDC3ConnectionException("Failed to connect to " + webSocketUrl, error); + }); + } + + @OnOpen + public void onOpen(Session session) { + Logger.info("WebSocket connection opened to {}", webSocketUrl); + this.session = session; + this.connected = true; + CompletableFuture pending = connectionFuture; + if (pending != null) { + pending.complete(null); + } + } + + @OnMessage + public void onMessage(String message) { + try { + @SuppressWarnings("unchecked") + Map messageMap = getConverter().getObjectMapper().readValue(message, Map.class); + + Logger.debug("Received message: {}", MessageLogging.summarise(messageMap)); + if (Logger.isPayloadEnabled()) { + Logger.payload("Received message: {}", MessageLogging.redact(messageMap)); + } + + + // Dispatch to all registered listeners + listeners.forEach((id, listener) -> { + try { + if (listener.filter(messageMap)) { + listener.action(messageMap); + } + } catch (Exception e) { + Logger.error("Error in listener {}: {}", id, e.getMessage()); + } + }); + } catch (IOException e) { + Logger.error("Failed to parse message: {}", e.getMessage()); + } + } + + @OnClose + public void onClose(Session session, CloseReason closeReason) { + this.connected = false; + this.session = null; + + CompletableFuture pendingDisconnect = disconnectFuture; + if (pendingDisconnect != null) { + // We asked for this close, so it is the expected end of the WSCPGoodbye exchange. + Logger.info("WebSocket connection closed: {}", closeReason.getReasonPhrase()); + pendingDisconnect.complete(null); + return; + } + + if (closeExpected) { + Logger.info("WebSocket connection closed: {}", closeReason.getReasonPhrase()); + return; + } + + // Nobody asked for this. Fail anything still waiting rather than letting callers find + // out only when their next request times out. + Logger.warn("WebSocket connection to {} was closed unexpectedly ({}: {}). " + + "Reconnecting is the application's responsibility.", + webSocketUrl, closeReason.getCloseCode(), closeReason.getReasonPhrase()); + + CompletableFuture pendingConnect = connectionFuture; + if (pendingConnect != null && !pendingConnect.isDone()) { + pendingConnect.completeExceptionally(new FDC3ConnectionException( + "WebSocket closed before the connection was established: " + + closeReason.getReasonPhrase())); + } + + listeners.clear(); + } + + @OnError + public void onError(Session session, Throwable error) { + Logger.error("WebSocket error: {}", error.getMessage()); + CompletableFuture pending = connectionFuture; + if (pending != null && !pending.isDone()) { + pending.completeExceptionally(error); + } + } + + @Override + public String createUUID() { + return UUID.randomUUID().toString(); + } + + /** + * Logs an outbound message. The first message of every connection is + * {@code WSCPApplicationConnect}, which carries {@code payload.sharedSecret}, so the body is + * only ever written to the payload trace logger and only after redaction. + */ + private static void logOutbound(Map message) { + Logger.debug("Sending message: {}", MessageLogging.summarise(message)); + if (Logger.isPayloadEnabled()) { + Logger.payload("Sending message: {}", MessageLogging.redact(message)); + } + } + + @Override + public CompletionStage post(Map message) { + Session openSession = session; + if (openSession == null || !openSession.isOpen()) { + return CompletableFuture.failedFuture( + new IllegalStateException("WebSocket is not connected")); + } + + CompletableFuture sent = new CompletableFuture<>(); + try { + String json = getConverter().toJson(message); + logOutbound(message); + + // The send is asynchronous, so its outcome has to be reported through the handler. + // Ignoring it made post() report success for sends that never happened, leaving + // callers to wait out the full exchange timeout instead of failing immediately. + openSession.getAsyncRemote().sendText(json, result -> { + if (result.isOK()) { + sent.complete(null); + } else { + sent.completeExceptionally(result.getException()); + } + }); + } catch (Exception e) { + sent.completeExceptionally(e); + } + return sent; + } + + @Override + public void register(RegisterableListener listener) { + if (listener.getId() == null) { + throw new IllegalArgumentException("Listener must have ID set"); + } + listeners.put(listener.getId(), listener); + } + + @Override + public void unregister(String id) { + listeners.remove(id); + } + + @Override + public CompletionStage disconnect() { + closeExpected = true; + + Session openSession = session; + if (openSession == null || !openSession.isOpen()) { + listeners.clear(); + connected = false; + releaseResources(); + return CompletableFuture.completedFuture(null); + } + + CompletableFuture closed = new CompletableFuture<>(); + disconnectFuture = closed; + + // Send WSCPGoodbye and let the Desktop Agent close the socket (WSCP acceptor role). + Map goodbye = new HashMap<>(); + goodbye.put("type", "WSCPGoodbye"); + Map meta = new HashMap<>(); + meta.put("timestamp", OffsetDateTime.now()); + goodbye.put("meta", meta); + + try { + String json = getConverter().toJson(goodbye); + logOutbound(goodbye); + openSession.getBasicRemote().sendText(json); + } catch (Exception e) { + Logger.error("Failed to send WSCPGoodbye: {}", e.getMessage()); + try { + openSession.close(); + } catch (IOException closeError) { + Logger.error("Error closing WebSocket: {}", closeError.getMessage()); + closed.complete(null); + } + } + + return closed + .orTimeout(5, TimeUnit.SECONDS) + .handle((ignored, error) -> { + if (error != null) { + Logger.warn("Timed out waiting for Desktop Agent to close after WSCPGoodbye: {}", + error.getMessage()); + try { + if (session != null && session.isOpen()) { + session.close(); + } + } catch (IOException e) { + Logger.error("Error closing WebSocket after timeout: {}", e.getMessage()); + } + } + listeners.clear(); + connected = false; + disconnectFuture = null; + releaseResources(); + return null; + }); + } + + /** + * Returns whether the WebSocket is currently connected. + * + * @return true if connected, false otherwise + */ + public boolean isConnected() { + return connected && session != null && session.isOpen(); + } + + /** Releases the thread pools held by the container and the timeout scheduler. */ + private void releaseResources() { + shutdownContainer(); + shutdownScheduler(); + } + + /** + * Shuts down the retained container. + *

+ * {@code WebSocketContainer} declares no lifecycle method, but implementations start thread + * pools that outlive the connection. Tyrus exposes {@code shutdown()} on its container, so + * it is called reflectively rather than compiling against a specific implementation. + */ + private void shutdownContainer() { + WebSocketContainer toShutDown = container; + if (toShutDown == null) { + return; + } + container = null; + + try { + toShutDown.getClass().getMethod("shutdown").invoke(toShutDown); + } catch (NoSuchMethodException e) { + Logger.debug("WebSocket container {} has no shutdown() method; nothing to release", + toShutDown.getClass().getName()); + } catch (Exception e) { + Logger.warn("Failed to shut down the WebSocket container: {}", e.getMessage()); + } + } +} diff --git a/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultChannelSelector.java b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultChannelSelector.java new file mode 100644 index 00000000..70705907 --- /dev/null +++ b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultChannelSelector.java @@ -0,0 +1,60 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent.ui; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.ui.ChannelSelector; + +/** + * A default no-op implementation of {@link ChannelSelector} for use when channel selection + * UI is not needed or is handled externally. + *

+ * This implementation does nothing when called - it doesn't display any UI and + * never triggers the channel change callback. Use this when: + *

    + *
  • Your application doesn't use user channels
  • + *
  • Channel selection is handled by a different mechanism
  • + *
  • You're testing without a UI
  • + *
+ */ +public class DefaultChannelSelector implements ChannelSelector { + + @Override + public CompletionStage connect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage disconnect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public void setChannelChangeCallback(Consumer callback) { + // No-op: this implementation never changes channels + } + + @Override + public void updateChannel(String channelId, List availableChannels) { + // No-op: this implementation doesn't display any UI + } +} diff --git a/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultIntentResolver.java b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultIntentResolver.java new file mode 100644 index 00000000..81706c0a --- /dev/null +++ b/fdc3-get-agent/src/main/java/org/finos/fdc3/getagent/ui/DefaultIntentResolver.java @@ -0,0 +1,150 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent.ui; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.errors.ResolveError; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.ui.IntentResolutionChoice; +import org.finos.fdc3.api.ui.IntentResolver; + +/** + * A configurable default implementation of {@link IntentResolver} for use when intent resolution + * UI is not needed or is handled externally. + *

+ * The behavior can be configured using {@link ResolverBehavior}: + *

    + *
  • {@link ResolverBehavior#USE_FIRST} - Automatically selects the first intent and first app
  • + *
  • {@link ResolverBehavior#CANCEL} - Returns null (indicating user cancellation)
  • + *
  • {@link ResolverBehavior#THROW_ERROR} - Throws a ResolveError
  • + *
+ */ +public class DefaultIntentResolver implements IntentResolver { + + /** + * Defines the behavior of the DefaultIntentResolver when asked to resolve an intent. + */ + public enum ResolverBehavior { + /** + * Automatically select the first intent and first application. + * This is useful for testing or when only one option is expected. + */ + USE_FIRST, + + /** + * Return null, indicating the user cancelled the resolution. + * This will cause the raiseIntent call to fail with UserCancelled. + */ + CANCEL, + + /** + * Throw an error indicating no resolver is available. + * This will cause the raiseIntent call to fail with ResolverUnavailable. + */ + THROW_ERROR + } + + private final ResolverBehavior behavior; + + /** + * Creates a DefaultIntentResolver with the default behavior of {@link ResolverBehavior#USE_FIRST}. + */ + public DefaultIntentResolver() { + this(ResolverBehavior.USE_FIRST); + } + + /** + * Creates a DefaultIntentResolver with the specified behavior. + * + * @param behavior the behavior to use when resolving intents + */ + public DefaultIntentResolver(ResolverBehavior behavior) { + this.behavior = behavior != null ? behavior : ResolverBehavior.USE_FIRST; + } + + @Override + public CompletionStage connect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage disconnect() { + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletionStage chooseIntent(List appIntents, Context context) { + switch (behavior) { + case USE_FIRST: + return resolveWithFirst(appIntents); + + case CANCEL: + return CompletableFuture.completedFuture(null); + + case THROW_ERROR: + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new RuntimeException(ResolveError.ResolverUnavailable.toString())); + return future; + + default: + return CompletableFuture.completedFuture(null); + } + } + + private CompletionStage resolveWithFirst(List appIntents) { + if (appIntents == null || appIntents.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + AppIntent firstIntent = appIntents.get(0); + if (firstIntent.getIntent() == null || firstIntent.getApps() == null || firstIntent.getApps().length == 0) { + return CompletableFuture.completedFuture(null); + } + + List apps = Arrays.asList(firstIntent.getApps()); + AppMetadata firstApp = apps.get(0); + + AppIdentifier appIdentifier = new AppIdentifier( + firstApp.getAppId(), + firstApp.getInstanceId(), + firstApp.getDesktopAgent() + ); + + IntentResolutionChoice choice = new IntentResolutionChoice( + firstIntent.getIntent().getName(), + appIdentifier + ); + + return CompletableFuture.completedFuture(choice); + } + + /** + * Gets the behavior configured for this resolver. + * + * @return the resolver behavior + */ + public ResolverBehavior getBehavior() { + return behavior; + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentMetadata.java b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/CucumberSpringConfiguration.java similarity index 60% rename from fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentMetadata.java rename to fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/CucumberSpringConfiguration.java index 6297789f..fd321677 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentMetadata.java +++ b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/CucumberSpringConfiguration.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,16 @@ * limitations under the License. */ -package com.finos.fdc3.api.metadata; +package org.finos.fdc3.getagent; + +import org.springframework.test.context.ContextConfiguration; + +import io.cucumber.spring.CucumberContextConfiguration; /** - * Intent descriptor + * Configures Spring for Cucumber test execution. */ -public interface IntentMetadata { - /** The unique name of the intent that can be invoked by the raiseIntent call */ - public String getName(); - - /** A friendly display name for the intent that should be used to render UI elements */ - public String getDisplayName(); +@CucumberContextConfiguration +@ContextConfiguration(classes = TestSpringConfig.class) +public class CucumberSpringConfiguration { } diff --git a/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/RunCucumberTest.java b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/RunCucumberTest.java new file mode 100644 index 00000000..1b044835 --- /dev/null +++ b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/RunCucumberTest.java @@ -0,0 +1,41 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent; + +import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.IncludeEngines; +import org.junit.platform.suite.api.Suite; + +import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.OBJECT_FACTORY_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME; + +/** + * JUnit Platform Suite entry point so Maven Surefire discovers Cucumber scenarios. + */ +@Suite +@IncludeEngines("cucumber") +@ConfigurationParameter(key = FEATURES_PROPERTY_NAME, value = "classpath:features") +@ConfigurationParameter( + key = GLUE_PROPERTY_NAME, + value = "org.finos.fdc3.getagent,org.finos.fdc3.getagent.steps,org.finos.cucumbertestingsteps.steps") +@ConfigurationParameter(key = OBJECT_FACTORY_PROPERTY_NAME, value = "io.cucumber.spring.SpringFactory") +@ConfigurationParameter( + key = PLUGIN_PROPERTY_NAME, + value = "pretty,summary,junit:target/cucumber-reports/cucumber.xml,html:target/cucumber-reports/cucumber.html") +public class RunCucumberTest {} diff --git a/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/TestSpringConfig.java b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/TestSpringConfig.java new file mode 100644 index 00000000..8654b21e --- /dev/null +++ b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/TestSpringConfig.java @@ -0,0 +1,44 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent; + +import org.finos.cucumbertestingsteps.world.PropsWorld; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ScopedProxyMode; + +import io.cucumber.spring.ScenarioScope; + +/** + * Spring configuration for Cucumber tests. + * + * Scans GetAgent-specific step definitions and generic steps from cucumber-testing-steps. + */ +@Configuration +@ComponentScan(basePackages = { + "org.finos.fdc3.getagent.steps", + "org.finos.cucumbertestingsteps.steps" +}) +public class TestSpringConfig { + + @Bean + @ScenarioScope(proxyMode = ScopedProxyMode.NO) + public PropsWorld propsWorld() { + return new PropsWorld(); + } +} diff --git a/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/steps/GetAgentSteps.java b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/steps/GetAgentSteps.java new file mode 100644 index 00000000..4eeb06fe --- /dev/null +++ b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/steps/GetAgentSteps.java @@ -0,0 +1,110 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent.steps; + +import static org.finos.cucumbertestingsteps.support.MatchingUtils.handleResolve; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.getagent.GetAgent; +import org.finos.fdc3.getagent.GetAgentParams; +import org.finos.fdc3.getagent.support.MockWebSocketServer; + +import io.cucumber.java.After; +import io.cucumber.java.Before; +import io.cucumber.java.en.Given; +import org.finos.cucumbertestingsteps.world.PropsWorld; + +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +/** + * Domain-specific Cucumber steps for GetAgent WSCP integration tests. + */ +public class GetAgentSteps { + + private final PropsWorld world; + private MockWebSocketServer activeServer; + + public GetAgentSteps(PropsWorld world) { + this.world = world; + } + + @Before + public void registerGetAgentFunction() { + world.set("getAgent", (Function>) GetAgent::getAgent); + } + + @After + public void stopMockServer() { + if (activeServer != null) { + activeServer.stop(); + activeServer = null; + } + } + + @Given("a mock WebSocket server in {string}") + public void createMockServer(String name) throws Exception { + if (activeServer != null) { + activeServer.stop(); + } + MockWebSocketServer server = new MockWebSocketServer(); + server.start(); + activeServer = server; + world.put(name, server); + } + + @Given("{string} will accept pairing for sharedSecret {string} as appId {string} instanceId {string}") + public void acceptPairing(String serverName, String secret, String appId, String instanceId) { + getServer(serverName).acceptPairing(secret, appId, instanceId); + } + + @Given("{string} will reject pairing with message {string}") + public void rejectPairing(String serverName, String message) { + getServer(serverName).rejectPairing(message); + } + + @Given("{string} will timeout on WSCP handshake") + public void timeoutPairing(String serverName) { + getServer(serverName).timeoutPairing(); + } + + @Given("{string} will return provider {string} fdc3Version {string}") + public void setProvider(String serverName, String provider, String version) { + getServer(serverName).setImplementationMetadata(provider, version); + } + + @Given("{string} is GetAgentParams with webSocketUrl {string} sharedSecret {string}") + public void buildParams(String name, String url, String secret) throws Exception { + world.put(name, GetAgentParams.builder() + .webSocketUrl((String) handleResolve(url, world)) + .sharedSecret(secret) + .build()); + } + + @Given("{string} is GetAgentParams with webSocketUrl {string} sharedSecret {string} timeout {long}") + public void buildParamsWithTimeout(String name, String url, String secret, long timeout) throws Exception { + world.put(name, GetAgentParams.builder() + .webSocketUrl((String) handleResolve(url, world)) + .sharedSecret(secret) + .timeoutMs(timeout) + .build()); + } + + private MockWebSocketServer getServer(String name) { + return (MockWebSocketServer) world.get(name); + } +} diff --git a/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/support/MockWebSocketServer.java b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/support/MockWebSocketServer.java new file mode 100644 index 00000000..5d53c011 --- /dev/null +++ b/fdc3-get-agent/src/test/java/org/finos/fdc3/getagent/support/MockWebSocketServer.java @@ -0,0 +1,299 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.getagent.support; + +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArrayList; + +import jakarta.websocket.CloseReason; +import jakarta.websocket.OnClose; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.ServerEndpoint; + +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.schema.AddContextListenerResponseMeta; +import org.finos.fdc3.schema.GetInfoRequest; +import org.finos.fdc3.schema.GetInfoResponse; +import org.finos.fdc3.schema.GetInfoResponsePayload; +import org.finos.fdc3.schema.GetInfoResponseType; +import org.finos.fdc3.schema.ProtocolVersion; +import org.finos.fdc3.schema.SchemaConverter; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnect; +import org.finos.fdc3.schema.WebSocketConnectionProtocolApplicationConnectMeta; +import org.finos.fdc3.schema.WebSocketConnectionProtocolConnectFailed; +import org.finos.fdc3.schema.WebSocketConnectionProtocolConnectFailedPayload; +import org.finos.fdc3.schema.WebSocketConnectionProtocolConnectFailedType; +import org.finos.fdc3.schema.WebSocketConnectionProtocolDesktopAgentConnect; +import org.finos.fdc3.schema.WebSocketConnectionProtocolDesktopAgentConnectPayload; +import org.finos.fdc3.schema.WebSocketConnectionProtocolDesktopAgentConnectType; +import org.finos.fdc3.schema.WebSocketConnectionProtocolGoodbye; +import org.glassfish.tyrus.server.Server; + +/** + * Mock WebSocket server for testing GetAgent WSCP handshake. + */ +@ServerEndpoint("/fdc3/ws") +public class MockWebSocketServer { + + /** Tyrus's marker for "bind to any free port"; see {@link #start()}. */ + private static final int EPHEMERAL_PORT = -1; + + private static final SchemaConverter converter = new SchemaConverter(); + + private static final CopyOnWriteArrayList sessions = new CopyOnWriteArrayList<>(); + private static volatile MockWebSocketServer currentInstance; + + private Server server; + private int port; + + private String acceptedSharedSecret; + private String responseAppId; + private String responseInstanceId; + private String rejectMessage; + private boolean shouldTimeout; + private String providerName = "test-provider"; + private String fdc3Version = "2.0"; + + private WebSocketConnectionProtocolApplicationConnect lastApplicationConnect; + private WebSocketConnectionProtocolGoodbye lastGoodbye; + + /** + * Starts on an ephemeral port. + *

+ * Tyrus reads {@code -1} as "ask the operating system for a free port", and reports the port + * actually bound from {@link Server#getPort()} once started. Note that {@code 0} would not + * work here: Tyrus maps it to its own default of 8025. + *

+ * Choosing a random port in a fixed range instead, as this once did, meant a run could + * collide with anything already listening there, including a concurrently running copy of + * this suite. + */ + public void start() throws Exception { + server = new Server("localhost", EPHEMERAL_PORT, "/", null, MockWebSocketServer.class); + currentInstance = this; + server.start(); + port = server.getPort(); + } + + public void stop() { + if (server != null) { + server.stop(); + server = null; + } + currentInstance = null; + sessions.clear(); + } + + public String getUrl() { + return "ws://localhost:" + port + "/fdc3/ws"; + } + + public void acceptPairing(String sharedSecret, String appId, String instanceId) { + acceptedSharedSecret = sharedSecret; + responseAppId = appId; + responseInstanceId = instanceId; + rejectMessage = null; + shouldTimeout = false; + } + + public void rejectPairing(String message) { + acceptedSharedSecret = null; + rejectMessage = message; + shouldTimeout = false; + } + + public void timeoutPairing() { + shouldTimeout = true; + } + + public void setImplementationMetadata(String provider, String version) { + providerName = provider; + fdc3Version = version; + } + + public WebSocketConnectionProtocolApplicationConnect getLastApplicationConnect() { + return lastApplicationConnect; + } + + public WebSocketConnectionProtocolGoodbye getLastGoodbye() { + return lastGoodbye; + } + + @OnOpen + public void onOpen(Session session) { + sessions.add(session); + } + + @OnClose + public void onClose(Session session, CloseReason reason) { + sessions.remove(session); + } + + @OnMessage + public void onMessage(String message, Session session) { + try { + String type = extractType(message); + MockWebSocketServer instance = currentInstance; + if (instance == null) { + return; + } + + if ("WSCPApplicationConnect".equals(type)) { + WebSocketConnectionProtocolApplicationConnect connect = + converter.fromJson(message, WebSocketConnectionProtocolApplicationConnect.class); + instance.lastApplicationConnect = connect; + instance.handleConnectRequest(connect, session); + } else if ("WSCPGoodbye".equals(type)) { + try { + instance.lastGoodbye = + converter.fromJson(message, WebSocketConnectionProtocolGoodbye.class); + } catch (IOException parseError) { + // Still record that goodbye was received even if typed parse fails + WebSocketConnectionProtocolGoodbye goodbye = new WebSocketConnectionProtocolGoodbye(); + goodbye.setType(org.finos.fdc3.schema.WebSocketConnectionProtocolGoodbyeType.WSCP_GOODBYE); + instance.lastGoodbye = goodbye; + } + // WSCP: the acceptor closes the connection after receiving goodbye + try { + session.close(); + } catch (IOException closeError) { + closeError.printStackTrace(); + } + } else if ("getInfoRequest".equals(type)) { + GetInfoRequest request = converter.fromJson(message, GetInfoRequest.class); + instance.handleGetInfoRequest(request, session); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private String extractType(String json) throws IOException { + return converter.getObjectMapper().readTree(json).path("type").asText(null); + } + + private void handleConnectRequest( + WebSocketConnectionProtocolApplicationConnect request, Session session) { + if (shouldTimeout) { + return; + } + + String connectionAttemptUuid = request.getMeta().getConnectionAttemptUUID(); + String sharedSecret = request.getPayload().getSharedSecret(); + + try { + String responseJson; + + if (rejectMessage != null) { + responseJson = buildFailedResponse(connectionAttemptUuid, rejectMessage); + } else if (acceptedSharedSecret != null + && acceptedSharedSecret.equals(sharedSecret)) { + responseJson = buildSuccessResponse(connectionAttemptUuid); + } else { + responseJson = buildFailedResponse(connectionAttemptUuid, "Invalid or unknown sharedSecret"); + } + + session.getBasicRemote().sendText(responseJson); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void handleGetInfoRequest(GetInfoRequest request, Session session) throws IOException { + GetInfoResponse response = new GetInfoResponse(); + response.setType(GetInfoResponseType.GET_INFO_RESPONSE); + + AddContextListenerResponseMeta meta = new AddContextListenerResponseMeta(); + meta.setRequestUUID(request.getMeta().getRequestUUID()); + meta.setResponseUUID(UUID.randomUUID().toString()); + meta.setTimestamp(OffsetDateTime.now()); + meta.setSource(request.getMeta().getSource()); + response.setMeta(meta); + + GetInfoResponsePayload payload = new GetInfoResponsePayload(); + payload.setImplementationMetadata(buildImplementationMetadata()); + response.setPayload(payload); + + session.getBasicRemote().sendText(converter.toJson(response)); + } + + private ImplementationMetadata buildImplementationMetadata() { + ImplementationMetadata implMeta = new ImplementationMetadata(); + implMeta.setFdc3Version(fdc3Version); + implMeta.setProvider(providerName); + implMeta.setProviderVersion("1.0.0"); + + AppMetadata appMeta = new AppMetadata(); + appMeta.setAppId(responseAppId); + appMeta.setInstanceId(responseInstanceId); + implMeta.setAppMetadata(appMeta); + + ImplementationMetadata.OptionalFeatures optFeatures = new ImplementationMetadata.OptionalFeatures(); + optFeatures.setUserChannelMembershipAPIs(true); + optFeatures.setDesktopAgentBridging(false); + implMeta.setOptionalFeatures(optFeatures); + + return implMeta; + } + + private String buildSuccessResponse(String connectionAttemptUuid) throws IOException { + WebSocketConnectionProtocolDesktopAgentConnect response = + new WebSocketConnectionProtocolDesktopAgentConnect(); + + WebSocketConnectionProtocolApplicationConnectMeta meta = + new WebSocketConnectionProtocolApplicationConnectMeta(); + meta.setConnectionAttemptUUID(connectionAttemptUuid); + meta.setTimestamp(OffsetDateTime.now()); + response.setMeta(meta); + + response.setType( + WebSocketConnectionProtocolDesktopAgentConnectType.WSCP_DESKTOP_AGENT_CONNECT); + + WebSocketConnectionProtocolDesktopAgentConnectPayload payload = + new WebSocketConnectionProtocolDesktopAgentConnectPayload(); + payload.setProtocolVersion(ProtocolVersion.THE_10); + payload.setImplementationMetadata(buildImplementationMetadata()); + response.setPayload(payload); + + return converter.toJson(response); + } + + private String buildFailedResponse(String connectionAttemptUuid, String message) throws IOException { + WebSocketConnectionProtocolConnectFailed response = + new WebSocketConnectionProtocolConnectFailed(); + + WebSocketConnectionProtocolApplicationConnectMeta meta = + new WebSocketConnectionProtocolApplicationConnectMeta(); + meta.setConnectionAttemptUUID(connectionAttemptUuid); + meta.setTimestamp(OffsetDateTime.now()); + response.setMeta(meta); + + response.setType(WebSocketConnectionProtocolConnectFailedType.WSCP_CONNECT_FAILED); + + WebSocketConnectionProtocolConnectFailedPayload payload = + new WebSocketConnectionProtocolConnectFailedPayload(); + payload.setMessage(message); + response.setPayload(payload); + + return converter.toJson(response); + } +} diff --git a/fdc3-get-agent/src/test/resources/features/get-agent.feature b/fdc3-get-agent/src/test/resources/features/get-agent.feature new file mode 100644 index 00000000..eeacc813 --- /dev/null +++ b/fdc3-get-agent/src/test/resources/features/get-agent.feature @@ -0,0 +1,59 @@ +Feature: GetAgent WebSocket Connection + + Background: Test Setup + Given a mock WebSocket server in "server" + + Scenario: Successful connection with valid pairing + Given "server" will accept pairing for sharedSecret "test-secret" as appId "test-app" instanceId "test-instance" + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" + When I wait for "{getAgent}" using argument "{params}" + And "{result}" is not null + When I call "{server}" with "getLastApplicationConnect" + And I refer to "{result}" as "wscpConnect" + Then "{wscpConnect}" is an object with the following contents + | payload.sharedSecret | + | test-secret | + + Scenario: Connection fails with invalid pairing + Given "server" will reject pairing with message "Access denied" + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "wrong-secret" + When I wait for "{getAgent}" using argument "{params}" + And "{result}" is an error with message "Connection failed: Access denied" + + Scenario: Connection times out + Given "server" will timeout on WSCP handshake + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" timeout 2000 + When I wait for "{getAgent}" using argument "{params}" + And "{result}" is an error + + Scenario: GetAgent returns implementation metadata + Given "server" will accept pairing for sharedSecret "test-secret" as appId "test-app" instanceId "test-instance" + Given "server" will return provider "test-provider" fdc3Version "2.0" + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" + When I wait for "{getAgent}" using argument "{params}" + When I call "{result}" with "getInfo" + And "{result}" is an object with the following contents + | provider | fdc3Version | + | test-provider | 2.0 | + + Scenario: Reconnect with the same sharedSecret + Given "server" will accept pairing for sharedSecret "test-secret" as appId "test-app" instanceId "test-instance" + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" + When I wait for "{getAgent}" using argument "{params}" + Given "reconnectParams" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" + When I wait for "{getAgent}" using argument "{reconnectParams}" + When I call "{server}" with "getLastApplicationConnect" + And I refer to "{result}" as "wscpReconnect" + Then "{wscpReconnect}" is an object with the following contents + | payload.sharedSecret | + | test-secret | + + Scenario: Disconnect sends WSCPGoodbye + Given "server" will accept pairing for sharedSecret "test-secret" as appId "test-app" instanceId "test-instance" + Given "params" is GetAgentParams with webSocketUrl "{server.url}" sharedSecret "test-secret" + When I wait for "{getAgent}" using argument "{params}" + When I refer to "{result}" as "agent" + When I call "{agent}" with "disconnect" + When I call "{server}" with "getLastGoodbye" + And I refer to "{result}" as "goodbye" + Then "{goodbye}" is not null diff --git a/fdc3-java-workbench/README.md b/fdc3-java-workbench/README.md new file mode 100644 index 00000000..653cd828 --- /dev/null +++ b/fdc3-java-workbench/README.md @@ -0,0 +1,83 @@ +# FDC3 Java Workbench + +JavaFX desktop port of the [FDC3 Workbench](https://github.com/finos/FDC3/tree/master/toolbox/fdc3-workbench) +for testing Desktop Agent interoperability. Targets **FDC3 3.0** only. + +## Features + +- Connect to a Desktop Agent via WSCP (protocol URL, env vars, or Connect dialog) +- Context template library (create / edit / broadcast / reset defaults) +- Raise intent / raiseIntentForContext with optional target and `getResult()` display +- Intent listeners with optional context / channel / private-channel results +- User channels: join, leave, broadcast, context listeners +- App channels: getOrCreate, broadcast, listeners +- Right-hand listener panels and system log + +## Prerequisites + +- Java 17+ +- A running FDC3 3.0 Desktop Agent (e.g. FDC3-Sail) + +## Building + +From the `fdc3-java-api` root: + +```bash +mvn clean package -pl fdc3-java-workbench -am +``` + +Executable shaded JAR: + +`fdc3-java-workbench/target/fdc3-java-workbench-1.0.0-SNAPSHOT.jar` + +## Running + +### Dev (JavaFX plugin) + +```bash +mvn -pl fdc3-java-workbench javafx:run +``` + +### Shaded JAR + +JavaFX native libraries must be available on the module/classpath for your OS. +Prefer `javafx:run` for local development, or the macOS `.app` below for Sail launches. + +```bash +java -DFDC3_WEBSOCKET_URL=ws://localhost:8090/fdc3/ws \ + -DFDC3_CONNECTION_SECRET=your-pairing-secret \ + -jar fdc3-java-workbench/target/fdc3-java-workbench-1.0.0-SNAPSHOT.jar +``` + +### Connection sources (priority order) + +1. Protocol handler URL — `fdc3-java-workbench://launch?webSocketUrl=...&sharedSecret=...` +2. `FDC3_WEBSOCKET_URL` / `FDC3_CONNECTION_SECRET` (env or system properties) +3. **Connect** button in the UI + +### Using with FDC3-Sail + +1. Register the `fdc3-java-workbench://` protocol (build the macOS app below, or register manually) +2. Point Sail’s native app record at this workbench +3. Use **Open On Desktop** — Sail mints a pairing secret and launches via the protocol URL + +## macOS .app + +```bash +mvn package -pl fdc3-java-workbench -am -Pmacos-app +fdc3-java-workbench/scripts/macos/install-app.sh +``` + +## Layout + +Mirrors the web workbench: + +- Left tabs: Contexts | Intents | User Channels | App Channels +- Right tabs: Listeners | System Log +- Header: connection status + `getInfo()` summary + +## Notes + +- No FDC3 1.2 / 2.x compatibility mode +- JSON editing is a plain text editor (no remote schema validation) +- Context templates persist in Java `Preferences` under this package diff --git a/fdc3-java-workbench/dependency-reduced-pom.xml b/fdc3-java-workbench/dependency-reduced-pom.xml new file mode 100644 index 00000000..c94f03d6 --- /dev/null +++ b/fdc3-java-workbench/dependency-reduced-pom.xml @@ -0,0 +1,124 @@ + + + + fdc3-parent + org.finos.fdc3 + 1.0.0-SNAPSHOT + + 4.0.0 + fdc3-java-workbench + FDC3 Java Workbench + JavaFX port of the FDC3 Workbench for testing Desktop Agent interoperability (FDC3 3.0) + + + + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${maven.compiler.release} + + + + org.openjfx + javafx-maven-plugin + 0.0.8 + + org.finos.fdc3.workbench.WorkbenchApp + + + + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + org.finos.fdc3.workbench.WorkbenchApp + + ${project.version} + ${maven.build.timestamp} + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + + + + macos-app + + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + + jpackage-macos-app + package + + exec + + + bash + + ${project.basedir}/scripts/macos/build-app.sh + ${project.version} + + + + + + + + + + + + org.junit.jupiter + junit-jupiter + 5.10.1 + test + + + junit-jupiter-api + org.junit.jupiter + + + junit-jupiter-params + org.junit.jupiter + + + junit-jupiter-engine + org.junit.jupiter + + + + + + yyyy-MM-dd HH:mm:ss + 17.0.14 + + diff --git a/fdc3-java-workbench/pom.xml b/fdc3-java-workbench/pom.xml new file mode 100644 index 00000000..b5b860c0 --- /dev/null +++ b/fdc3-java-workbench/pom.xml @@ -0,0 +1,162 @@ + + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-java-workbench + FDC3 Java Workbench + JavaFX port of the FDC3 Workbench for testing Desktop Agent interoperability (FDC3 3.0) + + + 17.0.14 + yyyy-MM-dd HH:mm:ss + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + org.finos.fdc3 + fdc3-get-agent + ${project.version} + + + org.finos.fdc3 + fdc3-schema + ${project.version} + + + org.openjfx + javafx-controls + ${javafx.version} + + + com.fasterxml.jackson.core + jackson-databind + + + org.slf4j + slf4j-simple + + + org.junit.jupiter + junit-jupiter + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${maven.compiler.release} + + + + org.openjfx + javafx-maven-plugin + 0.0.8 + + org.finos.fdc3.workbench.WorkbenchApp + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + org.finos.fdc3.workbench.WorkbenchApp + + ${project.version} + ${maven.build.timestamp} + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + + + + + macos-app + + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + + jpackage-macos-app + package + + exec + + + bash + + ${project.basedir}/scripts/macos/build-app.sh + ${project.version} + + + + + + + + + + diff --git a/fdc3-java-workbench/scripts/macos/build-app.sh b/fdc3-java-workbench/scripts/macos/build-app.sh new file mode 100755 index 00000000..99da308c --- /dev/null +++ b/fdc3-java-workbench/scripts/macos/build-app.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Builds a macOS .app bundle with jpackage and registers the fdc3-java-workbench:// URL scheme. +# +# Usage (from repo root or fdc3-java-workbench): +# fdc3-java-workbench/scripts/macos/build-app.sh [app-version] +# +# Requires: JDK with jpackage (14+), macOS, a built shaded JAR in target/ + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODULE_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +APP_NAME="FDC3 Java Workbench" +MAIN_JAR="fdc3-java-workbench-1.0.0-SNAPSHOT.jar" +MAIN_CLASS="org.finos.fdc3.workbench.WorkbenchApp" +BUNDLE_ID="org.finos.fdc3.workbench" +URL_SCHEME="fdc3-java-workbench" +RESOURCE_DIR="$SCRIPT_DIR/jpackage-resources" + +APP_VERSION="${1:-1.0.0}" +APP_VERSION="${APP_VERSION/-SNAPSHOT/}" + +JAR_PATH="$MODULE_DIR/target/$MAIN_JAR" +INPUT_DIR="$MODULE_DIR/target/jpackage-input" +OUTPUT_DIR="$MODULE_DIR/target/jpackage-staging" +APP_BUNDLE="$OUTPUT_DIR/$APP_NAME.app" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS app bundles must be built on macOS" >&2 + exit 1 +fi + +if [[ ! -f "$JAR_PATH" ]]; then + echo "error: JAR not found at $JAR_PATH — run: mvn package -pl fdc3-java-workbench -am" >&2 + exit 1 +fi + +if ! command -v jpackage >/dev/null 2>&1; then + echo "error: jpackage not found on PATH (install a JDK that includes jpackage)" >&2 + exit 1 +fi + +echo "Building $APP_NAME.app (version $APP_VERSION)..." +rm -rf "$APP_BUNDLE" +mkdir -p "$INPUT_DIR" +cp "$JAR_PATH" "$INPUT_DIR/" + +jpackage \ + --type app-image \ + --name "$APP_NAME" \ + --input "$INPUT_DIR" \ + --main-jar "$MAIN_JAR" \ + --main-class "$MAIN_CLASS" \ + --app-version "$APP_VERSION" \ + --mac-package-identifier "$BUNDLE_ID" \ + --resource-dir "$RESOURCE_DIR" \ + --dest "$OUTPUT_DIR" + +if ! codesign --verify --deep --strict --verbose=2 "$APP_BUNDLE" >/dev/null 2>&1; then + echo "error: jpackage app bundle signature verification failed" >&2 + exit 1 +fi + +echo "" +echo "Built: $APP_BUNDLE" +echo "" +echo "Install and launch (recommended — clears Gatekeeper quarantine on copy):" +echo " $SCRIPT_DIR/install-app.sh" +echo "" +echo "Or manually:" +echo " open \"$APP_BUNDLE\"" +echo " open \"${URL_SCHEME}://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=test-secret\"" +echo "" +echo "If double-click in Finder does nothing, the app is unsigned — use install-app.sh" +echo "or right-click → Open once, then double-click will work." diff --git a/fdc3-java-workbench/scripts/macos/install-app.sh b/fdc3-java-workbench/scripts/macos/install-app.sh new file mode 100755 index 00000000..ad31f70c --- /dev/null +++ b/fdc3-java-workbench/scripts/macos/install-app.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Installs the jpackage-built .app to ~/Applications and launches it. +# +# Usage: +# fdc3-java-workbench/scripts/macos/install-app.sh +# +# Run build-app.sh (or mvn package -Pmacos-app) first. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODULE_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +APP_NAME="FDC3 Java Workbench" +SOURCE_APP="$MODULE_DIR/target/jpackage-staging/$APP_NAME.app" +DEST_DIR="${HOME}/Applications" +DEST_APP="$DEST_DIR/$APP_NAME.app" + +if [[ ! -d "$SOURCE_APP" ]]; then + echo "error: $SOURCE_APP not found — run: mvn package -pl fdc3-java-workbench -am -Pmacos-app" >&2 + exit 1 +fi + +echo "Quitting any running copy..." +pkill -x "$APP_NAME" 2>/dev/null || true +sleep 1 + +mkdir -p "$DEST_DIR" +echo "Installing to $DEST_APP..." +rm -rf "$DEST_APP" +ditto "$SOURCE_APP" "$DEST_APP" + +# Remove quarantine/Gatekeeper flags that block double-click from Finder. +xattr -cr "$DEST_APP" + +echo "Launching..." +open "$DEST_APP" + +echo "" +echo "Installed and launched. Double-click from ~/Applications should work now." +echo "First time only: if macOS still blocks it, open System Settings →" +echo "Privacy & Security → Open Anyway, or right-click the app → Open." diff --git a/fdc3-java-workbench/scripts/macos/jpackage-resources/Info.plist b/fdc3-java-workbench/scripts/macos/jpackage-resources/Info.plist new file mode 100644 index 00000000..3893022f --- /dev/null +++ b/fdc3-java-workbench/scripts/macos/jpackage-resources/Info.plist @@ -0,0 +1,47 @@ + + + + + LSMinimumSystemVersion + 10.11 + CFBundleDevelopmentRegion + English + CFBundleAllowMixedLocalizations + + CFBundleExecutable + FDC3 Java Workbench + CFBundleIconFile + FDC3 Java Workbench.icns + CFBundleIdentifier + org.finos.fdc3.workbench + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FDC3 Java Workbench + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + LSApplicationCategoryType + public.app-category.developer-tools + CFBundleVersion + 1.0.0 + NSHumanReadableCopyright + Copyright (C) FINOS + NSHighResolutionCapable + + CFBundleURLTypes + + + CFBundleURLName + FDC3 Java Workbench Launch + CFBundleURLSchemes + + fdc3-java-workbench + + + + + diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/WorkbenchApp.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/WorkbenchApp.java new file mode 100644 index 00000000..4848889a --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/WorkbenchApp.java @@ -0,0 +1,327 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench; + +import java.awt.Desktop; +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +import org.finos.fdc3.workbench.connection.ConnectionService; +import org.finos.fdc3.workbench.connection.ProtocolLaunchParams; +import org.finos.fdc3.workbench.service.WorkbenchServices; +import org.finos.fdc3.workbench.ui.tabs.AppChannelsTab; +import org.finos.fdc3.workbench.ui.tabs.ContextsTab; +import org.finos.fdc3.workbench.ui.tabs.IntentsTab; +import org.finos.fdc3.workbench.ui.tabs.UserChannelsTab; +import org.finos.fdc3.workbench.ui.workbench.ListenersPane; +import org.finos.fdc3.workbench.ui.workbench.SystemLogPane; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.geometry.Orientation; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.SplitPane; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextInputDialog; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +/** + * FDC3 Java Workbench — JavaFX desktop port of toolbox/fdc3-workbench (FDC3 3.0). + */ +public class WorkbenchApp extends Application { + + private static final AtomicReference PENDING_OPEN_URI = new AtomicReference<>(); + private static final AtomicReference ACTIVE = new AtomicReference<>(); + private static String[] launchArgs = new String[0]; + + private WorkbenchServices services; + private Label statusLabel; + private Button connectButton; + private Button disconnectButton; + private Button reconnectButton; + private TabPane leftTabs; + + public static void main(String[] args) { + launchArgs = args != null ? args : new String[0]; + registerOpenUriHandler(); + launch(args); + } + + @Override + public void start(Stage stage) { + ACTIVE.set(this); + services = new WorkbenchServices(); + services.getConnection().setOnConnected(agent -> { + refreshAfterConnect(); + setWorkbenchEnabled(true); + }); + services.getConnection().setOnDisconnected(v -> { + services.getListeners().clearAll(); + services.getChannels().clear(); + setWorkbenchEnabled(false); + }); + + BorderPane root = new BorderPane(); + root.getStyleClass().add("root"); + root.setTop(buildTop()); + root.setCenter(buildBody()); + + Scene scene = new Scene(root, 1280, 840); + var css = getClass().getResource("/workbench.css"); + if (css != null) { + scene.getStylesheets().add(css.toExternalForm()); + } + stage.setTitle("FDC3 Java Workbench"); + stage.setScene(scene); + stage.show(); + + Platform.runLater(this::initializeConnection); + } + + private VBox buildTop() { + VBox top = new VBox(); + top.getChildren().addAll(buildHeader(), buildConnectionBar()); + return top; + } + + private HBox buildHeader() { + Label title = new Label("FDC3 Java Workbench"); + title.getStyleClass().add("title-label"); + Label subtitle = new Label("FDC3 3.0 Desktop Agent testing harness"); + subtitle.getStyleClass().add("subtitle-label"); + + Label infoLabel = new Label(); + infoLabel.getStyleClass().add("subtitle-label"); + services.getAgentHolder().infoProperty().addListener((obs, o, n) -> { + if (n == null) { + infoLabel.setText(""); + } else { + String provider = n.getProvider() != null ? n.getProvider() : "?"; + String version = n.getFdc3Version() != null ? n.getFdc3Version() : "?"; + String appId = n.getAppMetadata() != null ? n.getAppMetadata().getAppId() : "?"; + infoLabel.setText(provider + " | FDC3 " + version + " | appId=" + appId); + } + }); + + Button docs = new Button("API Docs"); + docs.setOnAction(e -> openUrl("https://fdc3.finos.org/docs/api/overview")); + + HBox left = new HBox(12, new VBox(2, title, subtitle), infoLabel); + HBox box = new HBox(16, left, docs); + HBox.setHgrow(left, Priority.ALWAYS); + box.getStyleClass().add("header-bar"); + return box; + } + + private HBox buildConnectionBar() { + statusLabel = new Label(); + statusLabel.textProperty().bind(services.getAgentHolder().statusTextProperty()); + services.getAgentHolder().statusStyleProperty().addListener((obs, o, n) -> { + statusLabel.getStyleClass().setAll(n != null ? n : "status-disconnected"); + }); + statusLabel.getStyleClass().add("status-disconnected"); + + connectButton = new Button("Connect"); + connectButton.setOnAction(e -> promptAndConnect()); + disconnectButton = new Button("Disconnect"); + disconnectButton.setDisable(true); + disconnectButton.setOnAction(e -> services.getConnection().disconnect()); + reconnectButton = new Button("Reconnect"); + reconnectButton.setDisable(true); + reconnectButton.setOnAction(e -> services.getConnection().reconnect()); + + services.getAgentHolder().agentProperty().addListener((obs, o, n) -> { + boolean connected = n != null; + disconnectButton.setDisable(!connected); + reconnectButton.setDisable(connected || !services.getConnection().hasCredentials()); + connectButton.setDisable(connected || services.getConnection().connectingProperty().get()); + }); + services.getConnection().connectingProperty().addListener((obs, o, n) -> + connectButton.setDisable(Boolean.TRUE.equals(n) || services.getAgentHolder().isConnected())); + + HBox bar = new HBox(8, new Label("Status:"), statusLabel, connectButton, disconnectButton, reconnectButton); + bar.getStyleClass().add("connection-bar"); + return bar; + } + + private SplitPane buildBody() { + leftTabs = new TabPane(); + leftTabs.getTabs().addAll( + tab("Contexts", new ContextsTab(services)), + tab("Intents", new IntentsTab(services)), + tab("User Channels", new UserChannelsTab(services)), + tab("App Channels", new AppChannelsTab(services))); + + TabPane rightTabs = new TabPane(); + rightTabs.getTabs().addAll( + tab("Listeners", new ListenersPane(services)), + tab("System Log", new SystemLogPane(services))); + + VBox left = card(leftTabs); + VBox right = card(rightTabs); + SplitPane split = new SplitPane(left, right); + split.setOrientation(Orientation.HORIZONTAL); + split.setDividerPositions(0.62); + SplitPane.setResizableWithParent(left, true); + SplitPane.setResizableWithParent(right, true); + setWorkbenchEnabled(false); + return split; + } + + private static Tab tab(String title, javafx.scene.Node content) { + Tab t = new Tab(title, content); + t.setClosable(false); + return t; + } + + private static VBox card(javafx.scene.Node content) { + VBox box = new VBox(content); + VBox.setVgrow(content, Priority.ALWAYS); + box.getStyleClass().add("panel-card"); + box.setPadding(new Insets(8)); + VBox.setVgrow(box, Priority.ALWAYS); + return box; + } + + private void setWorkbenchEnabled(boolean enabled) { + if (leftTabs != null) { + leftTabs.setDisable(!enabled); + } + } + + private void initializeConnection() { + ConnectionService connection = services.getConnection(); + for (String arg : launchArgs) { + if (arg != null && arg.regionMatches(true, 0, ProtocolLaunchParams.SCHEME + "://", 0, + ProtocolLaunchParams.SCHEME.length() + 3)) { + services.getLog().info("connection", + "Protocol launch URL: " + ProtocolLaunchParams.redactLaunchUri(arg)); + } + } + Optional fromArgs = ProtocolLaunchParams.fromArgs(launchArgs); + if (fromArgs.isPresent()) { + connection.applyProtocolLaunch(fromArgs.get(), "command-line launch URL"); + return; + } + String pending = connection.takePendingOpenUri(); + if (pending == null) { + pending = PENDING_OPEN_URI.getAndSet(null); + } + if (pending != null) { + connection.applyProtocolUri(pending, "desktop open URI"); + return; + } + String url = ConnectionService.envOrProperty("FDC3_WEBSOCKET_URL"); + String secret = ConnectionService.envOrProperty("FDC3_CONNECTION_SECRET"); + if (url != null && secret != null) { + connection.setCredentials(url, secret); + services.getLog().info("connection", "Using WSCP connection config from environment"); + connection.connect(); + return; + } + services.getLog().info("connection", + "No WSCP credentials at startup. Click Connect, or launch from Sail via protocol URL."); + } + + private void promptAndConnect() { + TextInputDialog urlDialog = new TextInputDialog( + services.getConnection().getWebSocketUrl() != null + ? services.getConnection().getWebSocketUrl() + : "ws://localhost:8090/fdc3/ws"); + urlDialog.setTitle("WSCP WebSocket URL"); + urlDialog.setHeaderText("Enter Desktop Agent WebSocket URL"); + urlDialog.setContentText("WebSocket URL:"); + Optional url = urlDialog.showAndWait(); + if (url.isEmpty() || url.get().isBlank()) { + return; + } + TextInputDialog secretDialog = new TextInputDialog(); + secretDialog.setTitle("WSCP Shared Secret"); + secretDialog.setHeaderText("Enter pairing shared secret from the Desktop Agent"); + secretDialog.setContentText("Shared secret:"); + Optional secret = secretDialog.showAndWait(); + if (secret.isEmpty() || secret.get().isBlank()) { + return; + } + services.getConnection().setCredentials(url.get().trim(), secret.get().trim()); + services.getLog().info("connection", "Using user-provided WSCP connection config"); + services.getConnection().connect(); + } + + private void refreshAfterConnect() { + reconnectButton.setDisable(true); + services.getAgentHolder().getAgent().ifPresent(agent -> + agent.getUserChannels().thenAccept(channels -> Platform.runLater(() -> { + services.getChannels().getUserChannels().setAll(channels); + services.getLog().info("userChannels", "Loaded " + channels.size() + " user channels"); + })).exceptionally(err -> { + services.getLog().error("userChannels", err.getMessage()); + return null; + })); + services.getAgentHolder().getAgent().ifPresent(agent -> + agent.getCurrentChannel().thenAccept(opt -> Platform.runLater(() -> + services.getChannels().setCurrentUserChannel(opt.orElse(null))))); + } + + private void handleOpenUri(String uri) { + services.getLog().info("connection", "Received open URI: " + ProtocolLaunchParams.redactLaunchUri(uri)); + services.getConnection().applyProtocolUri(uri, "desktop open URI"); + } + + private static void openUrl(String url) { + try { + if (Desktop.isDesktopSupported()) { + Desktop.getDesktop().browse(URI.create(url)); + } + } catch (Exception e) { + Alert alert = new Alert(Alert.AlertType.INFORMATION, url); + alert.setHeaderText("Open in browser"); + alert.showAndWait(); + } + } + + private static boolean supportsOpenUriHandler() { + if (!Desktop.isDesktopSupported()) { + return false; + } + return Desktop.getDesktop().isSupported(Desktop.Action.APP_OPEN_URI); + } + + private static void registerOpenUriHandler() { + if (!supportsOpenUriHandler()) { + return; + } + Desktop.getDesktop().setOpenURIHandler(event -> { + String uri = event.getURI().toString(); + PENDING_OPEN_URI.set(uri); + WorkbenchApp instance = ACTIVE.get(); + if (instance != null) { + Platform.runLater(() -> instance.handleOpenUri(uri)); + } + }); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ConnectionService.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ConnectionService.java new file mode 100644 index 00000000..eb5da411 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ConnectionService.java @@ -0,0 +1,210 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.connection; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.getagent.GetAgent; +import org.finos.fdc3.getagent.GetAgentParams; +import org.finos.fdc3.proxy.DesktopAgentProxy; +import org.finos.fdc3.workbench.service.AgentHolder; +import org.finos.fdc3.workbench.service.SystemLogService; + +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; + +/** + * WSCP connect / disconnect / reconnect, matching fdc3-example-app semantics. + */ +public class ConnectionService { + + private final AgentHolder agentHolder; + private final SystemLogService log; + private final BooleanProperty connecting = new SimpleBooleanProperty(false); + + private String webSocketUrl; + private String sharedSecret; + private Consumer onConnected = a -> { + }; + private Consumer onDisconnected = v -> { + }; + + private final AtomicReference pendingOpenUri = new AtomicReference<>(); + + public ConnectionService(AgentHolder agentHolder, SystemLogService log) { + this.agentHolder = agentHolder; + this.log = log; + } + + public BooleanProperty connectingProperty() { + return connecting; + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getSharedSecret() { + return sharedSecret; + } + + public boolean hasCredentials() { + return webSocketUrl != null && sharedSecret != null; + } + + public void setOnConnected(Consumer onConnected) { + this.onConnected = onConnected != null ? onConnected : a -> { + }; + } + + public void setOnDisconnected(Consumer onDisconnected) { + this.onDisconnected = onDisconnected != null ? onDisconnected : v -> { + }; + } + + public void setCredentials(String webSocketUrl, String sharedSecret) { + this.webSocketUrl = webSocketUrl; + this.sharedSecret = sharedSecret; + } + + public void setPendingOpenUri(String uri) { + pendingOpenUri.set(uri); + } + + public String takePendingOpenUri() { + return pendingOpenUri.getAndSet(null); + } + + public void applyProtocolLaunch(ProtocolLaunchParams params, String source) { + setCredentials(params.getWebSocketUrl(), params.getSharedSecret()); + log.info("connection", "Using WSCP connection config from " + source); + if (agentHolder.isConnected()) { + disconnect(); + } + connect(); + } + + public boolean applyProtocolUri(String uri, String source) { + var parsed = ProtocolLaunchParams.parseLaunchUri(uri); + if (parsed.isEmpty()) { + log.error("connection", "Could not parse protocol launch URL from " + source); + return false; + } + applyProtocolLaunch(parsed.get(), source); + return true; + } + + public void connect() { + if (!hasCredentials()) { + log.error("connection", "WSCP connection config incomplete"); + return; + } + if (connecting.get()) { + return; + } + connecting.set(true); + agentHolder.setStatus("Connecting...", "status-disconnected"); + log.info("connection", "Connecting to Desktop Agent at: " + webSocketUrl); + + try { + GetAgentParams params = GetAgentParams.builder() + .timeoutMs(30000) + .webSocketUrl(webSocketUrl) + .sharedSecret(sharedSecret) + .build(); + + GetAgent.getAgent(params) + .thenAccept(this::handleConnected) + .exceptionally(error -> { + Platform.runLater(() -> handleConnectionError(error)); + return null; + }); + } catch (Exception e) { + handleConnectionError(e); + } + } + + public void reconnect() { + if (!hasCredentials()) { + log.error("connection", "webSocketUrl and sharedSecret required for reconnection"); + return; + } + log.info("connection", "Reconnecting to Desktop Agent..."); + agentHolder.setStatus("Reconnecting...", "status-disconnected"); + connect(); + } + + public void disconnect() { + DesktopAgent agent = agentHolder.agentProperty().get(); + if (agent == null) { + return; + } + log.info("connection", "Disconnecting from Desktop Agent..."); + if (agent instanceof DesktopAgentProxy proxy) { + try { + proxy.disconnect().toCompletableFuture().join(); + } catch (Exception e) { + log.error("connection", "Error during disconnect - " + e.getMessage()); + } + } + agentHolder.setAgent(null); + agentHolder.setInfo(null); + agentHolder.setStatus("Disconnected", "status-disconnected"); + log.info("connection", "Disconnected from Desktop Agent"); + onDisconnected.accept(null); + } + + private void handleConnected(DesktopAgent agent) { + Platform.runLater(() -> { + connecting.set(false); + agentHolder.setAgent(agent); + agentHolder.setStatus("Connected", "status-connected"); + log.info("connection", "Successfully connected to Desktop Agent"); + agent.getInfo() + .thenAccept(info -> Platform.runLater(() -> { + agentHolder.setInfo(info); + if (info != null && info.getAppMetadata() != null + && info.getAppMetadata().getInstanceId() != null) { + log.info("connection", + "Assigned instanceId: " + info.getAppMetadata().getInstanceId()); + } + })) + .exceptionally(error -> { + log.error("connection", "Could not retrieve getInfo() - " + error.getMessage()); + return null; + }); + onConnected.accept(agent); + }); + } + + private void handleConnectionError(Throwable error) { + connecting.set(false); + agentHolder.setStatus("Connection Failed", "status-error"); + log.error("connection", "Failed to connect - " + error.getMessage()); + } + + public static String envOrProperty(String key) { + String value = System.getenv(key); + if (value == null || value.isBlank()) { + value = System.getProperty(key); + } + return value == null || value.isBlank() ? null : value.trim(); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParams.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParams.java new file mode 100644 index 00000000..a67a63f6 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParams.java @@ -0,0 +1,154 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.connection; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; + +/** + * Parses WSCP launch parameters from a custom protocol handler URL. + *

+ * Example: + * {@code fdc3-java-workbench://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=...} + */ +public final class ProtocolLaunchParams { + + public static final String SCHEME = "fdc3-java-workbench"; + + private static final Pattern SHARED_SECRET_VALUE = + Pattern.compile("(?i)(sharedSecret=)[^&#\\s]*"); + + private final String webSocketUrl; + private final String sharedSecret; + + private ProtocolLaunchParams(String webSocketUrl, String sharedSecret) { + this.webSocketUrl = webSocketUrl; + this.sharedSecret = sharedSecret; + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getSharedSecret() { + return sharedSecret; + } + + public static Optional fromArgs(String[] args) { + if (args == null || args.length == 0) { + return Optional.empty(); + } + for (String arg : args) { + Optional parsed = parseLaunchUri(arg); + if (parsed.isPresent()) { + return parsed; + } + } + for (int i = 0; i < args.length; i++) { + if (!isSchemeUrl(args[i])) { + continue; + } + StringBuilder rebuilt = new StringBuilder(args[i].trim()); + for (int j = i + 1; j < args.length; j++) { + String part = args[j]; + if (part == null || part.isBlank()) { + continue; + } + if (isSchemeUrl(part)) { + break; + } + if (!rebuilt.toString().contains("?")) { + rebuilt.append('?'); + } + if (!part.startsWith("&")) { + rebuilt.append('&'); + } + rebuilt.append(part); + } + Optional parsed = parseLaunchUri(rebuilt.toString()); + if (parsed.isPresent()) { + return parsed; + } + } + return Optional.empty(); + } + + public static String redactLaunchUri(String uri) { + if (uri == null) { + return null; + } + return SHARED_SECRET_VALUE.matcher(uri).replaceAll("$1"); + } + + private static boolean isSchemeUrl(String value) { + return value != null + && value.regionMatches(true, 0, SCHEME + "://", 0, SCHEME.length() + 3); + } + + public static Optional parseLaunchUri(String uri) { + if (uri == null || uri.isBlank()) { + return Optional.empty(); + } + + String normalized = uri.trim(); + if (!normalized.regionMatches(true, 0, SCHEME + "://", 0, SCHEME.length() + 3)) { + return Optional.empty(); + } + + try { + int queryStart = normalized.indexOf('?'); + String rawQuery = queryStart >= 0 ? normalized.substring(queryStart + 1) : null; + if (rawQuery != null) { + int hash = rawQuery.indexOf('#'); + if (hash >= 0) { + rawQuery = rawQuery.substring(0, hash); + } + } + Map query = parseQuery(rawQuery); + String webSocketUrl = query.get("webSocketUrl"); + String sharedSecret = query.get("sharedSecret"); + if (webSocketUrl == null || webSocketUrl.isBlank() + || sharedSecret == null || sharedSecret.isBlank()) { + return Optional.empty(); + } + return Optional.of(new ProtocolLaunchParams(webSocketUrl, sharedSecret)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + private static Map parseQuery(String rawQuery) { + Map params = new HashMap<>(); + if (rawQuery == null || rawQuery.isEmpty()) { + return params; + } + for (String pair : rawQuery.split("&")) { + int separator = pair.indexOf('='); + if (separator <= 0) { + continue; + } + String key = URLDecoder.decode(pair.substring(0, separator), StandardCharsets.UTF_8); + String value = URLDecoder.decode(pair.substring(separator + 1), StandardCharsets.UTF_8); + params.put(key, value); + } + return params; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ContextTemplate.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ContextTemplate.java new file mode 100644 index 00000000..82265f60 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ContextTemplate.java @@ -0,0 +1,80 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.model; + +import java.util.Map; +import java.util.UUID; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * A named context template used by the workbench for broadcast / raiseIntent. + */ +public class ContextTemplate { + + private final String uuid; + private String id; + private JsonNode template; + + public ContextTemplate(String id, JsonNode template) { + this(UUID.randomUUID().toString(), id, template); + } + + public ContextTemplate(String uuid, String id, JsonNode template) { + this.uuid = uuid; + this.id = id; + this.template = template; + } + + public String getUuid() { + return uuid; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public JsonNode getTemplate() { + return template; + } + + public void setTemplate(JsonNode template) { + this.template = template; + } + + public String contextType() { + if (template != null && template.has("type") && template.get("type").isTextual()) { + return template.get("type").asText(); + } + return ""; + } + + @Override + public String toString() { + return id; + } + + public Map asMap(com.fasterxml.jackson.databind.ObjectMapper mapper) { + @SuppressWarnings("unchecked") + Map map = mapper.convertValue(template, Map.class); + return map; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ListenerRecord.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ListenerRecord.java new file mode 100644 index 00000000..f65c47e1 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/ListenerRecord.java @@ -0,0 +1,86 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.model; + +import org.finos.fdc3.api.types.Listener; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +/** + * UI model for a registered FDC3 listener shown in the right-hand workbench panel. + */ +public class ListenerRecord { + + public enum Kind { + CONTEXT, + INTENT, + APP_CHANNEL, + PRIVATE_CHANNEL + } + + private final String id; + private final Kind kind; + private final String label; + private final String channelId; + private final Listener listener; + private final StringProperty lastReceived = new SimpleStringProperty("(none)"); + + public ListenerRecord(String id, Kind kind, String label, String channelId, Listener listener) { + this.id = id; + this.kind = kind; + this.label = label; + this.channelId = channelId; + this.listener = listener; + } + + public String getId() { + return id; + } + + public Kind getKind() { + return kind; + } + + public String getLabel() { + return label; + } + + public String getChannelId() { + return channelId; + } + + public Listener getListener() { + return listener; + } + + public StringProperty lastReceivedProperty() { + return lastReceived; + } + + public void setLastReceived(String value) { + lastReceived.set(value); + } + + @Override + public String toString() { + if (channelId != null) { + return kind + " / " + channelId + " / " + label; + } + return kind + " / " + label; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/LogEntry.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/LogEntry.java new file mode 100644 index 00000000..b5f61962 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/model/LogEntry.java @@ -0,0 +1,73 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.model; + +import java.time.Instant; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +/** + * One row in the system log / a registered listener summary. + */ +public class LogEntry { + + private final Instant timestamp; + private final String type; + private final String message; + private final String body; + + public LogEntry(String type, String message) { + this(type, message, null); + } + + public LogEntry(String type, String message, String body) { + this.timestamp = Instant.now(); + this.type = type; + this.message = message; + this.body = body; + } + + public Instant getTimestamp() { + return timestamp; + } + + public String getType() { + return type; + } + + public String getMessage() { + return message; + } + + public String getBody() { + return body; + } + + public StringProperty displayProperty() { + String text = timestamp + " [" + type + "] " + message; + if (body != null && !body.isBlank()) { + text = text + "\n" + body; + } + return new SimpleStringProperty(text); + } + + @Override + public String toString() { + return displayProperty().get(); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/AgentHolder.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/AgentHolder.java new file mode 100644 index 00000000..0c132bc1 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/AgentHolder.java @@ -0,0 +1,79 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import java.util.Optional; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.metadata.ImplementationMetadata; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +/** + * Holds the connected {@link DesktopAgent} and cached {@link ImplementationMetadata}. + */ +public class AgentHolder { + + private final ObjectProperty agent = new SimpleObjectProperty<>(); + private final ObjectProperty info = new SimpleObjectProperty<>(); + private final StringProperty statusText = new SimpleStringProperty("Not Connected"); + private final StringProperty statusStyle = new SimpleStringProperty("status-disconnected"); + + public ObjectProperty agentProperty() { + return agent; + } + + public Optional getAgent() { + return Optional.ofNullable(agent.get()); + } + + public void setAgent(DesktopAgent desktopAgent) { + agent.set(desktopAgent); + } + + public ObjectProperty infoProperty() { + return info; + } + + public ImplementationMetadata getInfo() { + return info.get(); + } + + public void setInfo(ImplementationMetadata metadata) { + info.set(metadata); + } + + public StringProperty statusTextProperty() { + return statusText; + } + + public StringProperty statusStyleProperty() { + return statusStyle; + } + + public void setStatus(String text, String styleClass) { + statusText.set(text); + statusStyle.set(styleClass); + } + + public boolean isConnected() { + return agent.get() != null; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ContextTemplateStore.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ContextTemplateStore.java new file mode 100644 index 00000000..da547034 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ContextTemplateStore.java @@ -0,0 +1,141 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.prefs.Preferences; + +import org.finos.fdc3.workbench.model.ContextTemplate; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Context template library with defaults from classpath and Preferences persistence. + */ +public class ContextTemplateStore { + + private static final String PREF_KEY = "contextTemplates"; + + private final ObjectMapper mapper; + private final SystemLogService log; + private final Preferences prefs = Preferences.userNodeForPackage(ContextTemplateStore.class); + private final ObservableList templates = FXCollections.observableArrayList(); + + public ContextTemplateStore(ObjectMapper mapper, SystemLogService log) { + this.mapper = mapper; + this.log = log; + load(); + } + + public ObservableList getTemplates() { + return templates; + } + + public ObjectMapper getMapper() { + return mapper; + } + + public void load() { + templates.clear(); + String saved = prefs.get(PREF_KEY, null); + if (saved != null && !saved.isBlank()) { + try { + templates.addAll(parseList(mapper.readTree(saved))); + log.info("contexts", "Loaded " + templates.size() + " context templates from preferences"); + return; + } catch (IOException e) { + log.error("contexts", "Failed to load saved templates - " + e.getMessage()); + } + } + resetToDefaults(); + } + + public void resetToDefaults() { + templates.clear(); + try (InputStream in = ContextTemplateStore.class.getResourceAsStream("/contexts-default.json")) { + if (in == null) { + log.error("contexts", "contexts-default.json not found on classpath"); + return; + } + templates.addAll(parseList(mapper.readTree(in))); + persist(); + log.info("contexts", "Reset to " + templates.size() + " default context templates"); + } catch (IOException e) { + log.error("contexts", "Failed to load default templates - " + e.getMessage()); + } + } + + public void add(ContextTemplate template) { + templates.add(template); + persist(); + } + + public void update(ContextTemplate template) { + persist(); + } + + public void remove(ContextTemplate template) { + templates.remove(template); + persist(); + } + + public void persist() { + try { + ArrayNode array = mapper.createArrayNode(); + for (ContextTemplate t : templates) { + ObjectNode node = mapper.createObjectNode(); + node.put("uuid", t.getUuid()); + node.put("id", t.getId()); + node.set("template", t.getTemplate()); + array.add(node); + } + prefs.put(PREF_KEY, mapper.writeValueAsString(array)); + } catch (IOException | IllegalArgumentException e) { + // macOS Java Preferences reject values over ~8KB ("Value too long") + log.error("contexts", "Failed to persist templates - " + e.getMessage()); + } + } + + private List parseList(JsonNode root) { + List list = new ArrayList<>(); + if (root == null || !root.isArray()) { + return list; + } + for (Iterator it = root.elements(); it.hasNext();) { + JsonNode node = it.next(); + String id = node.path("id").asText("unnamed"); + JsonNode template = node.get("template"); + String uuid = node.has("uuid") ? node.get("uuid").asText() : null; + if (uuid != null) { + list.add(new ContextTemplate(uuid, id, template)); + } else { + list.add(new ContextTemplate(id, template)); + } + } + return list; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ListenerRegistry.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ListenerRegistry.java new file mode 100644 index 00000000..2199eb57 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ListenerRegistry.java @@ -0,0 +1,188 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import java.util.UUID; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.Listener; +import org.finos.fdc3.workbench.model.ListenerRecord; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Manages registered listeners shown in the right-hand workbench panel. + */ +public class ListenerRegistry { + + private final ObservableList contextListeners = FXCollections.observableArrayList(); + private final ObservableList intentListeners = FXCollections.observableArrayList(); + private final ObservableList appChannelListeners = FXCollections.observableArrayList(); + private final ObservableList privateChannelListeners = FXCollections.observableArrayList(); + + private final SystemLogService log; + private final ObjectMapper mapper; + + public ListenerRegistry(SystemLogService log, ObjectMapper mapper) { + this.log = log; + this.mapper = mapper; + } + + public ObservableList getContextListeners() { + return contextListeners; + } + + public ObservableList getIntentListeners() { + return intentListeners; + } + + public ObservableList getAppChannelListeners() { + return appChannelListeners; + } + + public ObservableList getPrivateChannelListeners() { + return privateChannelListeners; + } + + public void clearAll() { + unsubscribeAll(contextListeners); + unsubscribeAll(intentListeners); + unsubscribeAll(appChannelListeners); + unsubscribeAll(privateChannelListeners); + contextListeners.clear(); + intentListeners.clear(); + appChannelListeners.clear(); + privateChannelListeners.clear(); + } + + public ContextHandler contextHandler(ListenerRecord record) { + return (context, metadata) -> Platform.runLater(() -> { + try { + String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(context); + record.setLastReceived(json); + log.info("contextReceived", "Context received on " + record.getLabel(), json); + } catch (Exception e) { + record.setLastReceived(String.valueOf(context)); + } + }); + } + + public ListenerRecord addContextListener(String label, Listener listener, ContextHandler unused) { + ListenerRecord record = new ListenerRecord( + UUID.randomUUID().toString(), ListenerRecord.Kind.CONTEXT, label, null, listener); + contextListeners.add(record); + return record; + } + + public ListenerRecord trackContextListener(String label, Listener listener) { + ListenerRecord record = new ListenerRecord( + UUID.randomUUID().toString(), ListenerRecord.Kind.CONTEXT, label, null, listener); + contextListeners.add(record); + log.info("addContextListener", "Added context listener: " + label); + return record; + } + + public ListenerRecord trackIntentListener(String label, Listener listener) { + ListenerRecord record = new ListenerRecord( + UUID.randomUUID().toString(), ListenerRecord.Kind.INTENT, label, null, listener); + intentListeners.add(record); + log.info("addIntentListener", "Added intent listener: " + label); + return record; + } + + public ListenerRecord trackAppChannelListener(String channelId, String label, Listener listener) { + ListenerRecord record = new ListenerRecord( + UUID.randomUUID().toString(), ListenerRecord.Kind.APP_CHANNEL, label, channelId, listener); + appChannelListeners.add(record); + log.info("addContextListener", "Added app-channel listener on " + channelId + ": " + label); + return record; + } + + public ListenerRecord trackPrivateChannelListener(String channelId, String label, Listener listener) { + ListenerRecord record = new ListenerRecord( + UUID.randomUUID().toString(), ListenerRecord.Kind.PRIVATE_CHANNEL, label, channelId, listener); + privateChannelListeners.add(record); + log.info("addContextListener", "Added private-channel listener on " + channelId + ": " + label); + return record; + } + + public void remove(ListenerRecord record) { + try { + if (record.getListener() != null) { + record.getListener().unsubscribe().toCompletableFuture().join(); + } + } catch (Exception e) { + log.error("unsubscribe", e.getMessage()); + } + switch (record.getKind()) { + case CONTEXT -> contextListeners.remove(record); + case INTENT -> intentListeners.remove(record); + case APP_CHANNEL -> appChannelListeners.remove(record); + case PRIVATE_CHANNEL -> privateChannelListeners.remove(record); + } + log.info("unsubscribe", "Removed listener: " + record); + } + + public Context toContext(java.util.Map map) { + Context context = new Context(); + if (map != null) { + context.putAll(map); + } + return context; + } + + private void unsubscribeAll(ObservableList list) { + for (ListenerRecord record : new java.util.ArrayList<>(list)) { + try { + if (record.getListener() != null) { + record.getListener().unsubscribe().toCompletableFuture().join(); + } + } catch (Exception ignored) { + // best-effort cleanup on disconnect + } + } + } + + public void wirePrivateChannelEvents(PrivateChannel channel, String channelId) { + try { + channel.addEventListener("addContextListener", event -> + log.info("privateChannel", "addContextListener on " + channelId)); + channel.addEventListener("unsubscribe", event -> + log.info("privateChannel", "unsubscribe on " + channelId)); + channel.addEventListener("disconnect", event -> + log.info("privateChannel", "disconnect on " + channelId)); + } catch (Exception e) { + log.error("privateChannel", "Failed to wire events - " + e.getMessage()); + } + } + + public DesktopAgent requireAgent(AgentHolder holder) { + return holder.getAgent().orElseThrow(() -> new IllegalStateException("Not connected")); + } + + public Channel requireChannel(java.util.concurrent.CompletionStage stage) { + return stage.toCompletableFuture().join(); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ObservableChannelState.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ObservableChannelState.java new file mode 100644 index 00000000..60cadb96 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/ObservableChannelState.java @@ -0,0 +1,64 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import org.finos.fdc3.api.channel.Channel; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Observable user-channel and app-channel state for the UI. + */ +public class ObservableChannelState { + + private final ObservableList userChannels = FXCollections.observableArrayList(); + private final ObjectProperty currentUserChannel = new SimpleObjectProperty<>(); + private final StringProperty currentUserChannelId = new SimpleStringProperty("(none)"); + private final ObservableList appChannels = FXCollections.observableArrayList(); + + public ObservableList getUserChannels() { + return userChannels; + } + + public ObjectProperty currentUserChannelProperty() { + return currentUserChannel; + } + + public StringProperty currentUserChannelIdProperty() { + return currentUserChannelId; + } + + public ObservableList getAppChannels() { + return appChannels; + } + + public void setCurrentUserChannel(Channel channel) { + currentUserChannel.set(channel); + currentUserChannelId.set(channel == null ? "(none)" : channel.getId()); + } + + public void clear() { + userChannels.clear(); + setCurrentUserChannel(null); + appChannels.clear(); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/SystemLogService.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/SystemLogService.java new file mode 100644 index 00000000..491d7510 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/SystemLogService.java @@ -0,0 +1,55 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import org.finos.fdc3.workbench.model.LogEntry; + +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +/** + * Chronological system log shared by all workbench panels. + */ +public class SystemLogService { + + private final ObservableList entries = FXCollections.observableArrayList(); + + public ObservableList getEntries() { + return entries; + } + + public void info(String type, String message) { + append(new LogEntry(type, message)); + } + + public void info(String type, String message, String body) { + append(new LogEntry(type, message, body)); + } + + public void error(String type, String message) { + append(new LogEntry(type, "ERROR: " + message)); + } + + private void append(LogEntry entry) { + if (Platform.isFxApplicationThread()) { + entries.add(0, entry); + } else { + Platform.runLater(() -> entries.add(0, entry)); + } + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/WorkbenchServices.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/WorkbenchServices.java new file mode 100644 index 00000000..c7318441 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/service/WorkbenchServices.java @@ -0,0 +1,63 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.service; + +import org.finos.fdc3.workbench.connection.ConnectionService; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Shared services for the JavaFX workbench. + */ +public class WorkbenchServices { + + private final ObjectMapper mapper = new ObjectMapper(); + private final SystemLogService log = new SystemLogService(); + private final AgentHolder agentHolder = new AgentHolder(); + private final ConnectionService connection = new ConnectionService(agentHolder, log); + private final ContextTemplateStore contexts = new ContextTemplateStore(mapper, log); + private final ListenerRegistry listeners = new ListenerRegistry(log, mapper); + private final ObservableChannelState channels = new ObservableChannelState(); + + public ObjectMapper getMapper() { + return mapper; + } + + public SystemLogService getLog() { + return log; + } + + public AgentHolder getAgentHolder() { + return agentHolder; + } + + public ConnectionService getConnection() { + return connection; + } + + public ContextTemplateStore getContexts() { + return contexts; + } + + public ListenerRegistry getListeners() { + return listeners; + } + + public ObservableChannelState getChannels() { + return channels; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/common/JsonEditorPane.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/common/JsonEditorPane.java new file mode 100644 index 00000000..33cb7e6b --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/common/JsonEditorPane.java @@ -0,0 +1,82 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.common; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; + +/** + * Simple JSON text editor with format / validate helpers. + */ +public class JsonEditorPane extends BorderPane { + + private final TextArea editor = new TextArea(); + private final Label status = new Label(); + private final ObjectMapper mapper; + + public JsonEditorPane(ObjectMapper mapper) { + this.mapper = mapper; + editor.setWrapText(true); + editor.getStyleClass().add("log-view"); + Button format = new Button("Format"); + format.setOnAction(e -> formatJson()); + HBox toolbar = new HBox(8, format, status); + toolbar.setPadding(new Insets(0, 0, 6, 0)); + setTop(toolbar); + setCenter(editor); + setPrefHeight(220); + } + + public TextArea getEditor() { + return editor; + } + + public void setJson(JsonNode node) { + try { + editor.setText(node == null ? "" : mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node)); + status.setText(""); + } catch (Exception e) { + editor.setText(String.valueOf(node)); + status.setText(e.getMessage()); + } + } + + public JsonNode getJson() throws Exception { + String text = editor.getText(); + if (text == null || text.isBlank()) { + throw new IllegalArgumentException("JSON is empty"); + } + return mapper.readTree(text); + } + + private void formatJson() { + try { + JsonNode node = getJson(); + setJson(node); + status.setText("OK"); + } catch (Exception e) { + status.setText("Invalid JSON: " + e.getMessage()); + } + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/AppChannelsTab.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/AppChannelsTab.java new file mode 100644 index 00000000..85018b99 --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/AppChannelsTab.java @@ -0,0 +1,161 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.tabs; + +import java.util.Map; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.workbench.model.ContextTemplate; +import org.finos.fdc3.workbench.model.ListenerRecord; +import org.finos.fdc3.workbench.service.WorkbenchServices; + +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +/** + * App channels: getOrCreate, broadcast, addContextListener, discard (local). + */ +public class AppChannelsTab extends VBox { + + private final WorkbenchServices services; + private final TextField channelIdField = new TextField(); + private final ListView channelList = new ListView<>(); + private final ComboBox contextCombo = new ComboBox<>(); + private final TextField listenerType = new TextField(); + + public AppChannelsTab(WorkbenchServices services) { + this.services = services; + setSpacing(12); + setPadding(new Insets(12)); + getStyleClass().add("panel-card"); + + channelIdField.setPromptText("channel id"); + channelList.setItems(services.getChannels().getAppChannels()); + contextCombo.setItems(services.getContexts().getTemplates()); + listenerType.setPromptText("context type (blank = all)"); + + Button getOrCreate = new Button("Get or Create"); + getOrCreate.setOnAction(e -> getOrCreate()); + Button discard = new Button("Discard"); + discard.setOnAction(e -> { + Channel selected = channelList.getSelectionModel().getSelectedItem(); + if (selected != null) { + services.getChannels().getAppChannels().remove(selected); + services.getLog().info("appChannel", "Discarded local reference to " + selected.getId()); + } + }); + Button broadcast = new Button("Broadcast"); + broadcast.setOnAction(e -> broadcast()); + Button addListener = new Button("Add Context Listener"); + addListener.setOnAction(e -> addListener()); + + HBox createRow = new HBox(8, channelIdField, getOrCreate, discard); + HBox.setHgrow(channelIdField, Priority.ALWAYS); + HBox actionRow = new HBox(8, contextCombo, broadcast, listenerType, addListener); + + VBox.setVgrow(channelList, Priority.ALWAYS); + getChildren().addAll( + new Label("App Channels") {{ getStyleClass().add("section-title"); }}, + createRow, + new Label("Open app channels"), + channelList, + actionRow); + } + + private void getOrCreate() { + DesktopAgent agent = services.getAgentHolder().getAgent().orElse(null); + String id = channelIdField.getText(); + if (agent == null || id == null || id.isBlank()) { + return; + } + agent.getOrCreateChannel(id.trim()) + .thenAccept(channel -> Platform.runLater(() -> { + if (services.getChannels().getAppChannels().stream() + .noneMatch(c -> c.getId().equals(channel.getId()))) { + services.getChannels().getAppChannels().add(channel); + } + channelList.getSelectionModel().select(channel); + services.getLog().info("getOrCreateChannel", "Got channel " + channel.getId()); + })) + .exceptionally(err -> { + services.getLog().error("getOrCreateChannel", err.getMessage()); + return null; + }); + } + + private void broadcast() { + Channel channel = channelList.getSelectionModel().getSelectedItem(); + ContextTemplate template = contextCombo.getValue(); + if (channel == null || template == null) { + return; + } + Context context = toContext(template); + channel.broadcast(context) + .thenRun(() -> services.getLog().info("broadcast", + "Broadcast on app channel " + channel.getId(), pretty(context))) + .exceptionally(err -> { + services.getLog().error("broadcast", err.getMessage()); + return null; + }); + } + + private void addListener() { + Channel channel = channelList.getSelectionModel().getSelectedItem(); + if (channel == null) { + return; + } + String type = listenerType.getText(); + String label = (type == null || type.isBlank()) ? "(all)" : type.trim(); + String contextType = (type == null || type.isBlank()) ? null : type.trim(); + final ListenerRecord[] holder = new ListenerRecord[1]; + channel.addContextListener(contextType, (ctx, meta) -> { + if (holder[0] != null) { + services.getListeners().contextHandler(holder[0]).handleContext(ctx, meta); + } + }).thenAccept(listener -> Platform.runLater(() -> + holder[0] = services.getListeners().trackAppChannelListener(channel.getId(), label, listener) + )).exceptionally(err -> { + services.getLog().error("addContextListener", err.getMessage()); + return null; + }); + } + + private Context toContext(ContextTemplate template) { + Map map = template.asMap(services.getMapper()); + Context context = new Context(); + context.putAll(map); + return context; + } + + private String pretty(Object value) { + try { + return services.getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(value); + } catch (Exception e) { + return String.valueOf(value); + } + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/ContextsTab.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/ContextsTab.java new file mode 100644 index 00000000..20484e5b --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/ContextsTab.java @@ -0,0 +1,143 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.tabs; + +import org.finos.fdc3.workbench.model.ContextTemplate; +import org.finos.fdc3.workbench.service.WorkbenchServices; +import org.finos.fdc3.workbench.ui.common.JsonEditorPane; + +import javafx.geometry.Insets; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +/** + * Context template library (CRUD + JSON editor). + */ +public class ContextsTab extends BorderPane { + + private final WorkbenchServices services; + private final ListView list = new ListView<>(); + private final TextField nameField = new TextField(); + private final JsonEditorPane editor; + + public ContextsTab(WorkbenchServices services) { + this.services = services; + this.editor = new JsonEditorPane(services.getMapper()); + + list.setItems(services.getContexts().getTemplates()); + list.getSelectionModel().selectedItemProperty().addListener((obs, o, selected) -> { + if (selected != null) { + nameField.setText(selected.getId()); + editor.setJson(selected.getTemplate()); + } + }); + + Button create = new Button("New"); + create.setOnAction(e -> createTemplate()); + Button save = new Button("Save"); + save.setOnAction(e -> saveSelected()); + Button duplicate = new Button("Duplicate"); + duplicate.setOnAction(e -> duplicateSelected()); + Button delete = new Button("Delete"); + delete.setOnAction(e -> deleteSelected()); + Button reset = new Button("Reset Defaults"); + reset.setOnAction(e -> { + Alert confirm = new Alert(Alert.AlertType.CONFIRMATION, + "Replace all templates with shipped defaults?", ButtonType.OK, ButtonType.CANCEL); + confirm.showAndWait().ifPresent(btn -> { + if (btn == ButtonType.OK) { + services.getContexts().resetToDefaults(); + } + }); + }); + + HBox actions = new HBox(8, create, save, duplicate, delete, reset); + actions.setPadding(new Insets(0, 0, 8, 0)); + + VBox form = new VBox(8, + new Label("Name"), nameField, + new Label("Context JSON"), editor); + VBox.setVgrow(editor, Priority.ALWAYS); + + VBox left = new VBox(8, new Label("Templates"), list, actions); + VBox.setVgrow(list, Priority.ALWAYS); + left.setPrefWidth(280); + left.setPadding(new Insets(8)); + + form.setPadding(new Insets(8)); + setLeft(left); + setCenter(form); + getStyleClass().add("panel-card"); + + if (!list.getItems().isEmpty()) { + list.getSelectionModel().selectFirst(); + } + } + + private void createTemplate() { + try { + var node = services.getMapper().readTree("{\"type\":\"fdc3.instrument\",\"id\":{\"ticker\":\"AAPL\"}}"); + ContextTemplate created = new ContextTemplate("New context", node); + services.getContexts().add(created); + list.getSelectionModel().select(created); + } catch (Exception e) { + services.getLog().error("contexts", e.getMessage()); + } + } + + private void saveSelected() { + ContextTemplate selected = list.getSelectionModel().getSelectedItem(); + if (selected == null) { + return; + } + try { + selected.setId(nameField.getText().trim()); + selected.setTemplate(editor.getJson()); + services.getContexts().update(selected); + list.refresh(); + services.getLog().info("contexts", "Saved template: " + selected.getId()); + } catch (Exception e) { + services.getLog().error("contexts", e.getMessage()); + } + } + + private void duplicateSelected() { + ContextTemplate selected = list.getSelectionModel().getSelectedItem(); + if (selected == null) { + return; + } + ContextTemplate copy = new ContextTemplate(selected.getId() + " copy", selected.getTemplate().deepCopy()); + services.getContexts().add(copy); + list.getSelectionModel().select(copy); + } + + private void deleteSelected() { + ContextTemplate selected = list.getSelectionModel().getSelectedItem(); + if (selected == null) { + return; + } + services.getContexts().remove(selected); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/IntentsTab.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/IntentsTab.java new file mode 100644 index 00000000..63108aba --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/IntentsTab.java @@ -0,0 +1,332 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.tabs; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.workbench.model.ContextTemplate; +import org.finos.fdc3.workbench.model.ListenerRecord; +import org.finos.fdc3.workbench.service.WorkbenchServices; + +import com.fasterxml.jackson.core.type.TypeReference; + +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * Raise intent / raiseIntentForContext / addIntentListener with optional results. + */ +public class IntentsTab extends VBox { + + private final WorkbenchServices services; + private final ComboBox contextCombo = new ComboBox<>(); + private final ComboBox intentCombo = new ComboBox<>(); + private final ComboBox targetCombo = new ComboBox<>(); + private final TextField intentListenerField = new TextField(); + private final TextField contextFilterField = new TextField(); + private final TextArea resolutionArea = new TextArea(); + private final CheckBox returnResult = new CheckBox("Return intent result"); + private final ToggleGroup resultType = new ToggleGroup(); + private final RadioButton resultContext = new RadioButton("Context"); + private final RadioButton resultPrivateChannel = new RadioButton("Private channel"); + private final RadioButton resultAppChannel = new RadioButton("App channel"); + private final TextField resultAppChannelId = new TextField("result-channel"); + + public IntentsTab(WorkbenchServices services) { + this.services = services; + setSpacing(12); + setPadding(new Insets(12)); + getStyleClass().add("panel-card"); + + contextCombo.setItems(services.getContexts().getTemplates()); + contextCombo.setPrefWidth(280); + intentCombo.setEditable(true); + intentCombo.setPrefWidth(280); + intentCombo.getItems().setAll(loadIntentTypes()); + targetCombo.setPrefWidth(320); + targetCombo.setPromptText("(optional target)"); + intentListenerField.setPromptText("Intent name"); + contextFilterField.setPromptText("Optional context type filter"); + resolutionArea.setEditable(false); + resolutionArea.setPrefRowCount(8); + resolutionArea.getStyleClass().add("log-view"); + + resultContext.setToggleGroup(resultType); + resultPrivateChannel.setToggleGroup(resultType); + resultAppChannel.setToggleGroup(resultType); + resultContext.setSelected(true); + + Button findTargets = new Button("Find Targets"); + findTargets.setOnAction(e -> findTargets()); + Button raise = new Button("Raise Intent"); + raise.setOnAction(e -> raiseIntent(false)); + Button raiseForContext = new Button("Raise Intent For Context"); + raiseForContext.setOnAction(e -> raiseIntent(true)); + Button addListener = new Button("Add Intent Listener"); + addListener.setOnAction(e -> addIntentListener()); + + GridPane raiseGrid = new GridPane(); + raiseGrid.setHgap(8); + raiseGrid.setVgap(8); + raiseGrid.add(new Label("Context"), 0, 0); + raiseGrid.add(contextCombo, 1, 0); + raiseGrid.add(new Label("Intent"), 0, 1); + raiseGrid.add(intentCombo, 1, 1); + raiseGrid.add(new Label("Target"), 0, 2); + raiseGrid.add(targetCombo, 1, 2); + raiseGrid.add(new HBox(8, findTargets, raise, raiseForContext), 1, 3); + + VBox listenerBox = new VBox(8, + new Label("Intent listener"), + new HBox(8, intentListenerField, contextFilterField, addListener), + returnResult, + new HBox(12, resultContext, resultPrivateChannel, resultAppChannel, resultAppChannelId)); + + getChildren().addAll( + new Label("Intents") {{ getStyleClass().add("section-title"); }}, + raiseGrid, + new Label("Resolution / Result"), + resolutionArea, + listenerBox); + } + + private List loadIntentTypes() { + try (InputStream in = getClass().getResourceAsStream("/intent-types.json")) { + if (in == null) { + return List.of(); + } + return services.getMapper().readValue(in, new TypeReference>() {}); + } catch (Exception e) { + services.getLog().error("intents", "Failed to load intent types - " + e.getMessage()); + return new ArrayList<>(); + } + } + + private DesktopAgent agent() { + return services.getAgentHolder().getAgent().orElse(null); + } + + private Context selectedContext() { + ContextTemplate template = contextCombo.getValue(); + if (template == null) { + return null; + } + Map map = template.asMap(services.getMapper()); + Context context = new Context(); + context.putAll(map); + return context; + } + + private void findTargets() { + DesktopAgent agent = agent(); + Context context = selectedContext(); + String intent = intentCombo.getValue(); + if (agent == null || context == null || intent == null || intent.isBlank()) { + return; + } + agent.findIntent(intent.trim(), context) + .thenAccept(appIntent -> Platform.runLater(() -> { + targetCombo.getItems().clear(); + if (appIntent != null && appIntent.getApps() != null) { + targetCombo.getItems().addAll(java.util.Arrays.asList(appIntent.getApps())); + } + services.getLog().info("findIntent", + "Found " + targetCombo.getItems().size() + " apps for " + intent); + })) + .exceptionally(err -> { + services.getLog().error("findIntent", err.getMessage()); + return null; + }); + } + + private void raiseIntent(boolean forContext) { + DesktopAgent agent = agent(); + Context context = selectedContext(); + String intent = intentCombo.getValue(); + if (agent == null || context == null) { + return; + } + AppMetadata target = targetCombo.getValue(); + AppIdentifier appId = target; + + var stage = forContext + ? (target != null + ? agent.raiseIntentForContext(context, appId) + : agent.raiseIntentForContext(context)) + : (intent == null || intent.isBlank() + ? null + : (target != null + ? agent.raiseIntent(intent.trim(), context, appId) + : agent.raiseIntent(intent.trim(), context))); + + if (stage == null) { + services.getLog().error("raiseIntent", "Intent name required"); + return; + } + + stage.thenAccept(resolution -> Platform.runLater(() -> showResolution(resolution))) + .exceptionally(err -> { + services.getLog().error(forContext ? "raiseIntentForContext" : "raiseIntent", + err.getMessage()); + return null; + }); + } + + private void showResolution(IntentResolution resolution) { + StringBuilder sb = new StringBuilder(); + if (resolution.getSource() != null) { + sb.append("source: ").append(resolution.getSource().getAppId()); + if (resolution.getSource().getInstanceId() != null) { + sb.append(" / ").append(resolution.getSource().getInstanceId()); + } + sb.append('\n'); + } + if (resolution.getIntent() != null) { + sb.append("intent: ").append(resolution.getIntent()).append('\n'); + } + resolutionArea.setText(sb.toString()); + services.getLog().info("raiseIntent", "Intent raised", sb.toString()); + + resolution.getResult().thenAccept(result -> Platform.runLater(() -> { + try { + String json = services.getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(result); + resolutionArea.appendText("\nresult:\n" + json); + services.getLog().info("intentResult", "Received intent result", json); + if (result instanceof PrivateChannel privateChannel) { + services.getChannels().getAppChannels().add(privateChannel); + services.getListeners().wirePrivateChannelEvents(privateChannel, privateChannel.getId()); + } else if (result instanceof Channel channel) { + if (services.getChannels().getAppChannels().stream() + .noneMatch(c -> c.getId().equals(channel.getId()))) { + services.getChannels().getAppChannels().add(channel); + } + } + } catch (Exception e) { + resolutionArea.appendText("\nresult: " + result); + } + })).exceptionally(err -> { + services.getLog().info("intentResult", "No result / timeout: " + err.getMessage()); + return null; + }); + } + + private void addIntentListener() { + DesktopAgent agent = agent(); + String intent = intentListenerField.getText(); + if (agent == null || intent == null || intent.isBlank()) { + return; + } + String filter = contextFilterField.getText(); + String label = intent.trim() + (filter == null || filter.isBlank() ? "" : " [" + filter.trim() + "]"); + + final ListenerRecord[] holder = new ListenerRecord[1]; + var handler = (org.finos.fdc3.api.types.IntentHandler) (context, metadata) -> { + Platform.runLater(() -> { + try { + String json = services.getMapper().writerWithDefaultPrettyPrinter() + .writeValueAsString(context); + if (holder[0] != null) { + holder[0].setLastReceived(json); + } + services.getLog().info("intentReceived", "Intent " + intent + " received", json); + } catch (Exception e) { + if (holder[0] != null) { + holder[0].setLastReceived(String.valueOf(context)); + } + } + }); + return buildIntentResult(context); + }; + + var stage = (filter == null || filter.isBlank()) + ? agent.addIntentListener(intent.trim(), handler) + : agent.addIntentListenerWithContext(intent.trim(), filter.trim(), handler); + + stage.thenAccept(listener -> Platform.runLater(() -> + holder[0] = services.getListeners().trackIntentListener(label, listener) + )).exceptionally(err -> { + services.getLog().error("addIntentListener", err.getMessage()); + return null; + }); + } + + private CompletableFuture> buildIntentResult(Context raised) { + if (!returnResult.isSelected()) { + return CompletableFuture.completedFuture(Optional.empty()); + } + DesktopAgent agent = agent(); + if (agent == null) { + return CompletableFuture.completedFuture(Optional.empty()); + } + if (resultPrivateChannel.isSelected()) { + return agent.createPrivateChannel() + .thenApply(ch -> { + Platform.runLater(() -> { + services.getChannels().getAppChannels().add(ch); + services.getListeners().wirePrivateChannelEvents(ch, ch.getId()); + services.getLog().info("intentResult", "Returning private channel " + ch.getId()); + }); + return Optional.of(ch); + }) + .toCompletableFuture(); + } + if (resultAppChannel.isSelected()) { + String id = resultAppChannelId.getText(); + if (id == null || id.isBlank()) { + id = "result-channel"; + } + String channelId = id.trim(); + return agent.getOrCreateChannel(channelId) + .thenApply(ch -> { + Platform.runLater(() -> { + if (services.getChannels().getAppChannels().stream() + .noneMatch(c -> c.getId().equals(ch.getId()))) { + services.getChannels().getAppChannels().add(ch); + } + services.getLog().info("intentResult", "Returning app channel " + ch.getId()); + }); + return Optional.of(ch); + }) + .toCompletableFuture(); + } + // Return the raised context as the result by default + return CompletableFuture.completedFuture(Optional.of(raised)); + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/UserChannelsTab.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/UserChannelsTab.java new file mode 100644 index 00000000..9a6a6fff --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/tabs/UserChannelsTab.java @@ -0,0 +1,195 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.tabs; + +import java.util.Map; + +import org.finos.fdc3.api.DesktopAgent; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.workbench.model.ContextTemplate; +import org.finos.fdc3.workbench.model.ListenerRecord; +import org.finos.fdc3.workbench.service.WorkbenchServices; + +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; + +/** + * User channel join / leave / broadcast / addContextListener. + */ +public class UserChannelsTab extends VBox { + + private final WorkbenchServices services; + private final ComboBox channelCombo = new ComboBox<>(); + private final ComboBox contextCombo = new ComboBox<>(); + private final TextField listenerType = new TextField(); + private final Label currentLabel = new Label(); + + public UserChannelsTab(WorkbenchServices services) { + this.services = services; + setSpacing(12); + setPadding(new Insets(12)); + getStyleClass().add("panel-card"); + + channelCombo.setItems(services.getChannels().getUserChannels()); + channelCombo.setPrefWidth(280); + contextCombo.setItems(services.getContexts().getTemplates()); + contextCombo.setPrefWidth(280); + listenerType.setPromptText("context type (blank = all)"); + currentLabel.textProperty().bind(services.getChannels().currentUserChannelIdProperty()); + + Button refresh = new Button("Refresh"); + refresh.setOnAction(e -> refreshChannels()); + Button join = new Button("Join"); + join.setOnAction(e -> joinChannel()); + Button leave = new Button("Leave"); + leave.setOnAction(e -> leaveChannel()); + Button broadcast = new Button("Broadcast"); + broadcast.setOnAction(e -> broadcast()); + Button addListener = new Button("Add Context Listener"); + addListener.setOnAction(e -> addListener()); + + GridPane grid = new GridPane(); + grid.setHgap(8); + grid.setVgap(8); + grid.add(new Label("Current channel"), 0, 0); + grid.add(currentLabel, 1, 0); + grid.add(refresh, 2, 0); + grid.add(new Label("Join channel"), 0, 1); + grid.add(channelCombo, 1, 1); + grid.add(join, 2, 1); + grid.add(leave, 3, 1); + grid.add(new Label("Broadcast context"), 0, 2); + grid.add(contextCombo, 1, 2); + grid.add(broadcast, 2, 2); + grid.add(new Label("Listener type"), 0, 3); + grid.add(listenerType, 1, 3); + grid.add(addListener, 2, 3); + + getChildren().addAll(new Label("User Channels") {{ getStyleClass().add("section-title"); }}, grid); + } + + private DesktopAgent agent() { + return services.getAgentHolder().getAgent().orElse(null); + } + + private void refreshChannels() { + DesktopAgent agent = agent(); + if (agent == null) { + return; + } + agent.getUserChannels().thenAccept(channels -> Platform.runLater(() -> { + services.getChannels().getUserChannels().setAll(channels); + services.getLog().info("userChannels", "Refreshed " + channels.size() + " user channels"); + })); + agent.getCurrentChannel().thenAccept(opt -> Platform.runLater(() -> + services.getChannels().setCurrentUserChannel(opt.orElse(null)))); + } + + private void joinChannel() { + DesktopAgent agent = agent(); + Channel channel = channelCombo.getValue(); + if (agent == null || channel == null) { + return; + } + agent.joinUserChannel(channel.getId()) + .thenRun(() -> Platform.runLater(() -> { + services.getChannels().setCurrentUserChannel(channel); + services.getLog().info("joinUserChannel", "Joined " + channel.getId()); + })) + .exceptionally(err -> { + services.getLog().error("joinUserChannel", err.getMessage()); + return null; + }); + } + + private void leaveChannel() { + DesktopAgent agent = agent(); + if (agent == null) { + return; + } + agent.leaveCurrentChannel() + .thenRun(() -> Platform.runLater(() -> { + services.getChannels().setCurrentUserChannel(null); + services.getLog().info("leaveCurrentChannel", "Left current user channel"); + })) + .exceptionally(err -> { + services.getLog().error("leaveCurrentChannel", err.getMessage()); + return null; + }); + } + + private void broadcast() { + DesktopAgent agent = agent(); + ContextTemplate template = contextCombo.getValue(); + if (agent == null || template == null) { + return; + } + Context context = toContext(template); + agent.broadcast(context) + .thenRun(() -> services.getLog().info("broadcast", + "Broadcast " + template.getId(), pretty(context))) + .exceptionally(err -> { + services.getLog().error("broadcast", err.getMessage()); + return null; + }); + } + + private void addListener() { + DesktopAgent agent = agent(); + if (agent == null) { + return; + } + String type = listenerType.getText(); + String label = (type == null || type.isBlank()) ? "(all)" : type.trim(); + String contextType = (type == null || type.isBlank()) ? null : type.trim(); + + // Placeholder record so handler can update lastReceived once we have Listener + final ListenerRecord[] holder = new ListenerRecord[1]; + agent.addContextListener(contextType, (ctx, meta) -> { + if (holder[0] != null) { + services.getListeners().contextHandler(holder[0]).handleContext(ctx, meta); + } + }).thenAccept(listener -> Platform.runLater(() -> { + holder[0] = services.getListeners().trackContextListener(label, listener); + })).exceptionally(err -> { + services.getLog().error("addContextListener", err.getMessage()); + return null; + }); + } + + private Context toContext(ContextTemplate template) { + Map map = template.asMap(services.getMapper()); + Context context = new Context(); + context.putAll(map); + return context; + } + + private String pretty(Object value) { + try { + return services.getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(value); + } catch (Exception e) { + return String.valueOf(value); + } + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/ListenersPane.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/ListenersPane.java new file mode 100644 index 00000000..7f668d1a --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/ListenersPane.java @@ -0,0 +1,90 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.workbench; + +import org.finos.fdc3.workbench.model.ListenerRecord; +import org.finos.fdc3.workbench.service.WorkbenchServices; + +import javafx.beans.binding.Bindings; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.TitledPane; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +/** + * Right-hand listener lists (context / intent / app / private). + */ +public class ListenersPane extends VBox { + + private final WorkbenchServices services; + + public ListenersPane(WorkbenchServices services) { + this.services = services; + setSpacing(8); + setPadding(new Insets(8)); + + getChildren().addAll( + section("Context Listeners", services.getListeners().getContextListeners()), + section("Intent Listeners", services.getListeners().getIntentListeners()), + section("App Channel Listeners", services.getListeners().getAppChannelListeners()), + section("Private Channel Listeners", services.getListeners().getPrivateChannelListeners())); + } + + private TitledPane section(String title, javafx.collections.ObservableList items) { + ListView list = new ListView<>(items); + list.setCellFactory(lv -> new ListCell<>() { + @Override + protected void updateItem(ListenerRecord item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + setGraphic(null); + return; + } + Label label = new Label(); + label.textProperty().bind(Bindings.createStringBinding( + () -> item + "\nlast: " + abbreviate(item.lastReceivedProperty().get()), + item.lastReceivedProperty())); + Button remove = new Button("Remove"); + remove.setOnAction(e -> services.getListeners().remove(item)); + BorderPane row = new BorderPane(); + row.setCenter(label); + row.setRight(remove); + row.getStyleClass().add("listener-item"); + setGraphic(row); + } + }); + list.setPrefHeight(140); + TitledPane pane = new TitledPane(title, list); + pane.setExpanded(true); + VBox.setVgrow(pane, Priority.ALWAYS); + return pane; + } + + private static String abbreviate(String value) { + if (value == null) { + return ""; + } + String flat = value.replace('\n', ' '); + return flat.length() > 120 ? flat.substring(0, 117) + "..." : flat; + } +} diff --git a/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/SystemLogPane.java b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/SystemLogPane.java new file mode 100644 index 00000000..fc228f2a --- /dev/null +++ b/fdc3-java-workbench/src/main/java/org/finos/fdc3/workbench/ui/workbench/SystemLogPane.java @@ -0,0 +1,39 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.ui.workbench; + +import org.finos.fdc3.workbench.model.LogEntry; +import org.finos.fdc3.workbench.service.WorkbenchServices; + +import javafx.geometry.Insets; +import javafx.scene.control.ListView; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +/** + * Chronological system log. + */ +public class SystemLogPane extends VBox { + + public SystemLogPane(WorkbenchServices services) { + setPadding(new Insets(8)); + ListView list = new ListView<>(services.getLog().getEntries()); + list.getStyleClass().add("log-view"); + VBox.setVgrow(list, Priority.ALWAYS); + getChildren().add(list); + } +} diff --git a/fdc3-java-workbench/src/main/resources/contexts-default.json b/fdc3-java-workbench/src/main/resources/contexts-default.json new file mode 100644 index 00000000..47f58e91 --- /dev/null +++ b/fdc3-java-workbench/src/main/resources/contexts-default.json @@ -0,0 +1,595 @@ +[ + { + "id": "Action example", + "template": { + "type": "fdc3.action", + "action": "broadcast", + "channelId": "Channel 1", + "title": "Click to view Chart", + "context": { + "type": "fdc3.chart", + "instruments": [ + { + "type": "fdc3.instrument", + "id": { + "ticker": "EURUSD" + } + } + ], + "range": { + "type": "fdc3.timeRange", + "startTime": "2020-09-01T08:00:00.000Z", + "endTime": "2020-10-31T08:00:00.000Z" + }, + "style": "candle" + } + } + }, + { + "id": "Chart example", + "template": { + "type": "fdc3.chart", + "instruments": [ + { + "type": "fdc3.instrument", + "id": { + "ticker": "AAPL" + } + }, + { + "type": "fdc3.instrument", + "id": { + "ticker": "GOOG" + } + } + ], + "range": { + "type": "fdc3.timeRange", + "startTime": "2020-09-01T08:00:00.000Z", + "endTime": "2020-10-31T08:00:00.000Z" + }, + "style": "line" + } + }, + { + "id": "Chat Initialization example", + "template": { + "type": "fdc3.chat.initSettings", + "chatName": "Chat ABCD", + "members": { + "type": "fdc3.contactList", + "contacts": [ + { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane@mail.com" + } + }, + { + "type": "fdc3.contact", + "name": "John Doe", + "id": { + "email": "john@mail.com" + } + } + ] + }, + "options": { + "groupRecipients": true, + "isPublic": false, + "allowHistoryBrowsing": true, + "allowMessageCopy": true + }, + "message": { + "type": "fdc3.message", + "text": { + "text/plain": "Hey all, can we discuss the issue together? I attached a screenshot" + }, + "entities": { + "0": { + "type": "fdc3.fileAttachment", + "data": { + "name": "myImage.png", + "dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII" + } + } + } + } + } + }, + { + "id": "Chat Message example", + "template": { + "type": "fdc3.chat.message", + "chatRoom": { + "type": "fdc3.chat.room", + "providerName": "Symphony", + "id": { + "streamId": "j75xqXy25NBOdacUI3FNBH" + } + }, + "message": { + "type": "fdc3.message", + "text": { + "text/plain": "Hey all, can we discuss the issue together? I attached a screenshot" + }, + "entities": { + "0": { + "type": "fdc3.fileAttachment", + "data": { + "name": "myImage.png", + "dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII" + } + } + } + } + } + }, + { + "id": "Chat room example", + "template": { + "type": "fdc3.chat.room", + "providerName": "Symphony", + "id": { + "streamId": "j75xqXy25NBOdacUI3FNBH" + }, + "url": "http://symphony.com/ref/room/j75xqXy25NBOdacUI3FNBH___pqSsuJRdA", + "name": "My new room" + } + }, + { + "id": "Chat search example", + "template": { + "type": "fdc3.chat.searchCriteria", + "criteria": [ + { + "type": "fdc3.instrument", + "id": { + "ticker": "AAPL" + } + }, + { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + }, + { + "type": "fdc3.organization", + "name": "Symphony", + "id": { + "FDS_ID": "SYMPHONY" + } + }, + "#OrderID45788422" + ] + } + }, + { + "id": "Contact example", + "template": { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + } + }, + { + "id": "ContactList example", + "template": { + "type": "fdc3.contactList", + "contacts": [ + { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + }, + { + "type": "fdc3.contact", + "name": "John Doe", + "id": { + "email": "john.doe@mail.com" + } + } + ] + } + }, + { + "id": "Country example", + "template": { + "type": "fdc3.country", + "name": "Sweden", + "id": { + "ISOALPHA3": "SWE" + } + } + }, + { + "id": "Currency example", + "template": { + "type": "fdc3.currency", + "name": "US Dollar", + "id": { + "CURRENCY_ISOCODE": "USD" + } + } + }, + { + "id": "Email example", + "template": { + "type": "fdc3.email", + "recipients": { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@example.com" + } + }, + "subject": "The information you requested", + "textBody": "Blah, blah, blah ..." + } + }, + { + "id": "File attachment example", + "template": { + "type": "fdc3.fileAttachment", + "data": { + "name": "myImage.png", + "dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII" + } + } + }, + { + "id": "Instrument example - MSFT", + "template": { + "type": "fdc3.instrument", + "name": "Microsoft", + "id": { + "ticker": "MSFT", + "RIC": "MSFT.OQ", + "ISIN": "US5949181045" + } + } + }, + { + "id": "Instrument example - AAPL", + "template": { + "type": "fdc3.instrument", + "name": "Apple", + "id": { + "ticker": "AAPL" + } + } + }, + { + "id": "InstrumentList example", + "template": { + "type": "fdc3.instrumentList", + "instruments": [ + { + "type": "fdc3.instrument", + "id": { + "ticker": "AAPL" + } + }, + { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + } + ] + } + }, + { + "id": "Interaction example", + "template": { + "type": "fdc3.interaction", + "participants": { + "type": "fdc3.contactList", + "contacts": [ + { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + }, + { + "type": "fdc3.contact", + "name": "John Doe", + "id": { + "email": "john.doe@mail.com" + } + } + ] + }, + "interactionType": "Instant Message", + "timeRange": { + "type": "fdc3.timeRange", + "startTime": "2022-02-10T15:12:00Z" + }, + "description": "Laboris libero dapibus fames elit adipisicing eu, fermentum, dignissimos laboriosam, erat, risus qui deserunt. Praesentium! Reiciendis. Hic harum nostrud, harum potenti amet? Mauris. Pretium aliquid animi, eget eiusmod integer proident. Architecto ipsum blandit ducimus, possimus illum sunt illum necessitatibus ab litora sed, nonummy integer minus corrupti ducimus iste senectus accumsan, fugiat nostrud? Pede vero dictumst excepturi, iure earum consequuntur voluptatum", + "initiator": { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + }, + "origin": "Outlook" + } + }, + { + "id": "Message example", + "template": { + "type": "fdc3.message", + "text": { + "text/plain": "Hey all, can we discuss the issue together? I attached a screenshot and a chart link." + }, + "entities": { + "picture1": { + "type": "fdc3.fileAttachment", + "data": { + "name": "myImage.png", + "dataUri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII" + } + }, + "viewChart": { + "type": "fdc3.action", + "title": "Click to view Chart", + "intent": "ViewChart", + "context": { + "type": "fdc3.chart", + "instruments": [ + { + "type": "fdc3.instrument", + "id": { + "ticker": "EURUSD" + } + } + ], + "range": { + "type": "fdc3.timeRange", + "startTime": "2020-09-01T08:00:00.000Z", + "endTime": "2020-10-31T08:00:00.000Z" + }, + "style": "candle" + } + } + } + } + }, + { + "id": "Nothing example", + "template": { + "type": "fdc3.nothing" + } + }, + { + "id": "Order example", + "template": { + "type": "fdc3.order", + "name": "...", + "id": { + "myOMS": "12345" + }, + "details": { + "product": { + "type": "fdc3.product", + "id": { + "productId": "ABC123" + }, + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + } + } + } + } + }, + { + "id": "OrderList example", + "template": { + "type": "fdc3.orderList", + "orders": [ + { + "type": "fdc3.order", + "id": { + "myOMS": "ABC123" + } + }, + { + "type": "fdc3.order", + "id": { + "myOMS": "DEF456" + } + } + ] + } + }, + { + "id": "Organization example", + "template": { + "type": "fdc3.organization", + "name": "Cargill, Incorporated", + "id": { + "LEI": "QXZYQNMR4JZ5RIRN4T31", + "FDS_ID": "00161G-E" + } + } + }, + { + "id": "Position example", + "template": { + "type": "fdc3.position", + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "AAPL" + } + }, + "holding": 2000000 + } + }, + { + "id": "Portfolio example", + "template": { + "type": "fdc3.portfolio", + "positions": [ + { + "type": "fdc3.position", + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "AAPL" + } + }, + "holding": 2000000 + }, + { + "type": "fdc3.position", + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + }, + "holding": 1500000 + }, + { + "type": "fdc3.position", + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "IBM" + } + }, + "holding": 3000000 + } + ] + } + }, + { + "id": "Product example", + "template": { + "type": "fdc3.product", + "id": { + "productId": "ABC123" + }, + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + } + } + }, + { + "id": "TimeRange example", + "template": { + "type": "fdc3.timeRange", + "startTime": "2022-03-30T15:44:44Z", + "endTime": "2022-04-30T23:59:59Z" + } + }, + { + "id": "Trade example", + "template": { + "type": "fdc3.trade", + "name": "...", + "id": { + "myEMS": "12345" + }, + "product": { + "type": "fdc3.product", + "id": { + "productId": "ABC123" + }, + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + } + } + } + }, + { + "id": "TradeList example", + "template": { + "type": "fdc3.tradeList", + "trades": [ + { + "type": "fdc3.trade", + "name": "...", + "id": { + "myEMS": "12345" + }, + "product": { + "type": "fdc3.product", + "id": { + "productId": "ABC123" + }, + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "MSFT" + } + } + } + }, + { + "type": "fdc3.trade", + "id": { + "myEMS": "67890" + }, + "product": { + "type": "fdc3.product", + "id": { + "productId": "DEF456" + }, + "instrument": { + "type": "fdc3.instrument", + "id": { + "ticker": "TSLA" + } + } + } + } + ] + } + }, + { + "id": "Transaction result example", + "template": { + "type": "fdc3.transactionResult", + "status": "Updated", + "context": { + "type": "fdc3.contact", + "name": "Jane Doe", + "id": { + "email": "jane.doe@mail.com" + } + }, + "message": "record with id 'jane.doe@mail.com' was updated" + } + }, + { + "id": "Valuation example", + "template": { + "type": "fdc3.valuation", + "value": 500, + "price": 5, + "CURRENCY_ISOCODE": "USD", + "expiryTime": "2022-05-13T16:16:24+01:00" + } + } +] \ No newline at end of file diff --git a/fdc3-java-workbench/src/main/resources/intent-types.json b/fdc3-java-workbench/src/main/resources/intent-types.json new file mode 100644 index 00000000..2c868cc9 --- /dev/null +++ b/fdc3-java-workbench/src/main/resources/intent-types.json @@ -0,0 +1,21 @@ +[ + "CreateInteraction", + "CreateOrUpdateProfile", + "SendChatMessage", + "StartCall", + "StartChat", + "StartEmail", + "ViewAnalysis", + "ViewChart", + "ViewChat", + "ViewContact", + "ViewHoldings", + "ViewInstrument", + "ViewInteractions", + "ViewMessages", + "ViewNews", + "ViewOrders", + "ViewProfile", + "ViewQuote", + "ViewResearch" +] diff --git a/fdc3-java-workbench/src/main/resources/workbench.css b/fdc3-java-workbench/src/main/resources/workbench.css new file mode 100644 index 00000000..1f1324cb --- /dev/null +++ b/fdc3-java-workbench/src/main/resources/workbench.css @@ -0,0 +1,70 @@ +.root { + -fx-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + -fx-font-size: 13px; + -fx-background-color: #f5f6f8; +} + +.header-bar { + -fx-background-color: #ffffff; + -fx-padding: 12 16 12 16; + -fx-border-color: #acb2c0; + -fx-border-width: 0 0 1 0; +} + +.title-label { + -fx-font-size: 20px; + -fx-font-family: "Source Code Pro", "Menlo", monospace; + -fx-text-fill: #0086bf; +} + +.subtitle-label { + -fx-text-fill: #5b606f; + -fx-font-size: 12px; +} + +.connection-bar { + -fx-padding: 8 16 8 16; + -fx-spacing: 8; + -fx-background-color: #eef6fa; + -fx-border-color: #acb2c0; + -fx-border-width: 0 0 1 0; +} + +.status-connected { + -fx-text-fill: #008000; + -fx-font-weight: bold; +} + +.status-disconnected { + -fx-text-fill: #666666; +} + +.status-error { + -fx-text-fill: #c62828; + -fx-font-weight: bold; +} + +.panel-card { + -fx-background-color: #ffffff; + -fx-padding: 12; + -fx-border-color: #d0d4dc; + -fx-border-radius: 4; + -fx-background-radius: 4; +} + +.section-title { + -fx-font-size: 16px; + -fx-text-fill: #0086bf; + -fx-padding: 0 0 8 0; +} + +.log-view { + -fx-font-family: "Menlo", "Consolas", monospace; + -fx-font-size: 11px; +} + +.listener-item { + -fx-padding: 6 8 6 8; + -fx-border-color: #e0e3ea; + -fx-border-width: 0 0 1 0; +} diff --git a/fdc3-java-workbench/src/test/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParamsTest.java b/fdc3-java-workbench/src/test/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParamsTest.java new file mode 100644 index 00000000..79bde1f4 --- /dev/null +++ b/fdc3-java-workbench/src/test/java/org/finos/fdc3/workbench/connection/ProtocolLaunchParamsTest.java @@ -0,0 +1,54 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.workbench.connection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class ProtocolLaunchParamsTest { + + @Test + void parsesLaunchUri() { + Optional parsed = ProtocolLaunchParams.parseLaunchUri( + "fdc3-java-workbench://launch?webSocketUrl=ws%3A%2F%2Flocalhost%3A8090%2Ffdc3%2Fws&sharedSecret=secret"); + assertTrue(parsed.isPresent()); + assertEquals("ws://localhost:8090/fdc3/ws", parsed.get().getWebSocketUrl()); + assertEquals("secret", parsed.get().getSharedSecret()); + } + + @Test + void redactsSharedSecret() { + String redacted = ProtocolLaunchParams.redactLaunchUri( + "fdc3-java-workbench://launch?webSocketUrl=ws://x&sharedSecret=top-secret"); + assertTrue(redacted.contains("sharedSecret=")); + assertTrue(!redacted.contains("top-secret")); + } + + @Test + void fromArgsRejoinsAmpersandSplit() { + Optional parsed = ProtocolLaunchParams.fromArgs(new String[] { + "fdc3-java-workbench://launch?webSocketUrl=ws://localhost:8090/fdc3/ws", + "sharedSecret=abc" + }); + assertTrue(parsed.isPresent()); + assertEquals("abc", parsed.get().getSharedSecret()); + } +} diff --git a/fdc3-schema/pom.xml b/fdc3-schema/pom.xml new file mode 100644 index 00000000..f942155a --- /dev/null +++ b/fdc3-schema/pom.xml @@ -0,0 +1,322 @@ + + + 4.0.0 + + org.finos.fdc3 + fdc3-parent + 1.0.0-SNAPSHOT + + + fdc3-schema + FDC3 Schema Types + Generated Java classes for FDC3 API types from JSON Schema + + + ${project.build.directory}/schema-work + ${project.build.directory}/npm-work/node_modules/@finos/fdc3-schema/dist/schemas + ${project.build.directory}/npm-work/node_modules/@finos/fdc3-context/dist/schemas/context + + ${project.basedir}/src/main/schemas-overlay/api + ${fdc3.schema.work.dir}/api/api.schema.json + + + + + + org.finos.fdc3 + fdc3-standard + ${project.version} + + + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + none + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${maven.compiler.release} + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + populate-schema-work + process-sources + + copy-resources + + + ${fdc3.schema.work.dir} + true + + + ${fdc3.schema.source.dir}/api + api + + + ${fdc3.schema.source.dir}/bridging + bridging + + + ${fdc3.schema.source.dir}/bridgingAsyncAPI + bridgingAsyncAPI + + + ${fdc3.context.source.dir} + context + + + + + + copy-api-overlay + process-sources + + copy-resources + + + ${fdc3.schema.work.dir} + true + + + ${fdc3.schema.overlay.dir} + api + + README.md + + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + create-directories + initialize + + run + + + + + + + + + + + + + + + + + quicktype-api + process-sources + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delete-duplicate-classes + process-sources + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.github.eirslett + frontend-maven-plugin + 1.15.0 + + ${node.version} + ${npm.version} + ${project.build.directory}/npm-work + ${project.build.directory}/node-installation + + + + install-node-and-npm + generate-sources + + install-node-and-npm + + + + + npm-ci + generate-sources + + npm + + + ci --no-audit --no-fund + + + + + + + com.google.code.maven-replacer-plugin + replacer + 1.5.3 + + + add-standard-imports + process-sources + + replace + + + ${project.build.directory}/generated-sources/fdc3/org/finos/fdc3/schema + + *.java + + + + ^package org\.finos\.fdc3\.schema; + package org.finos.fdc3.schema; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.*; +import org.finos.fdc3.api.types.AppIdentifier; + + + true + + MULTILINE + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.4.0 + + + add-source + process-sources + + add-source + + + + ${project.build.directory}/generated-sources/fdc3 + + + + + + + + diff --git a/fdc3-schema/src/main/java/org/finos/fdc3/schema/NullHandlingMixin.java b/fdc3-schema/src/main/java/org/finos/fdc3/schema/NullHandlingMixin.java new file mode 100644 index 00000000..172744db --- /dev/null +++ b/fdc3-schema/src/main/java/org/finos/fdc3/schema/NullHandlingMixin.java @@ -0,0 +1,112 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.schema; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Jackson Mix-ins for FDC3 schema types to handle optional fields. + * + * Generated by scripts/generate-mixins.js - regenerate after schema changes. + * + * In JSON Schema, optional fields (not in "required" array) that don't allow null + * should be omitted when null, not serialized as "field": null. + * These mix-ins apply {@code @JsonInclude(NON_NULL)} to those fields. + * + * Note: Some types (AppIdentifier, AppMetadata, DisplayMetadata, Icon, Image, + * ImplementationMetadata, IntentMetadata) are now beans in fdc3-standard with + * {@code @JsonInclude(NON_NULL)} at class level, so they don't need mixins here. + */ +public final class NullHandlingMixin { + + private NullHandlingMixin() { + // Utility class + } + + /** + * Register all mix-ins with the given ObjectMapper. + * Note: Types from fdc3-standard (AppIdentifier, AppMetadata, DisplayMetadata, + * Icon, Image, ImplementationMetadata, IntentMetadata) already have proper + * JSON annotations and don't need mixins. + */ + public static void registerAll(ObjectMapper om) { + om.addMixIn(BroadcastEventPayload.class, BroadcastEventPayloadMixin.class); + om.addMixIn(Channel.class, ChannelMixin.class); + om.addMixIn(FindIntentRequestPayload.class, FindIntentRequestPayloadMixin.class); + om.addMixIn(FindIntentsByContextRequestPayload.class, FindIntentsByContextRequestPayloadMixin.class); + om.addMixIn(IntentEventPayload.class, IntentEventPayloadMixin.class); + om.addMixIn(OpenRequestPayload.class, OpenRequestPayloadMixin.class); + om.addMixIn(RaiseIntentForContextRequestPayload.class, RaiseIntentForContextRequestPayloadMixin.class); + om.addMixIn(RaiseIntentRequestPayload.class, RaiseIntentRequestPayloadMixin.class); + } + + // === Mix-in classes for schema types that need null handling === + + public static abstract class BroadcastEventPayloadMixin { + @JsonProperty("originatingApp") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getOriginatingApp(); + } + + public static abstract class ChannelMixin { + @JsonProperty("displayMetadata") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getDisplayMetadata(); + } + + public static abstract class FindIntentRequestPayloadMixin { + @JsonProperty("context") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getContext(); + + @JsonProperty("resultType") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract String getResultType(); + } + + public static abstract class FindIntentsByContextRequestPayloadMixin { + @JsonProperty("resultType") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract String getResultType(); + } + + public static abstract class IntentEventPayloadMixin { + @JsonProperty("originatingApp") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getOriginatingApp(); + } + + public static abstract class OpenRequestPayloadMixin { + @JsonProperty("context") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getContext(); + } + + public static abstract class RaiseIntentForContextRequestPayloadMixin { + @JsonProperty("app") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getApp(); + } + + public static abstract class RaiseIntentRequestPayloadMixin { + @JsonProperty("app") + @JsonInclude(JsonInclude.Include.NON_NULL) + abstract Object getApp(); + } +} diff --git a/fdc3-schema/src/main/java/org/finos/fdc3/schema/SchemaConverter.java b/fdc3-schema/src/main/java/org/finos/fdc3/schema/SchemaConverter.java new file mode 100644 index 00000000..dbf1e6ec --- /dev/null +++ b/fdc3-schema/src/main/java/org/finos/fdc3/schema/SchemaConverter.java @@ -0,0 +1,254 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.schema; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Converter for JSON to FDC3 API message types based on the "type" field in the JSON. + */ +public class SchemaConverter { + + private final ObjectMapper mapper; + + // Map of FDC3 message type strings to their corresponding Java classes + private static final Map> TYPE_MAP = new HashMap<>(); + + static { + // Request messages + TYPE_MAP.put("addContextListenerRequest", AddContextListenerRequest.class); + TYPE_MAP.put("addEventListenerRequest", AddEventListenerRequest.class); + TYPE_MAP.put("addIntentListenerRequest", AddIntentListenerRequest.class); + TYPE_MAP.put("broadcastRequest", BroadcastRequest.class); + TYPE_MAP.put("clearContextRequest", ClearContextRequest.class); + TYPE_MAP.put("contextListenerUnsubscribeRequest", ContextListenerUnsubscribeRequest.class); + TYPE_MAP.put("createPrivateChannelRequest", CreatePrivateChannelRequest.class); + TYPE_MAP.put("eventListenerUnsubscribeRequest", EventListenerUnsubscribeRequest.class); + TYPE_MAP.put("findInstancesRequest", FindInstancesRequest.class); + TYPE_MAP.put("findIntentRequest", FindIntentRequest.class); + TYPE_MAP.put("findIntentsByContextRequest", FindIntentsByContextRequest.class); + TYPE_MAP.put("getCurrentChannelRequest", GetCurrentChannelRequest.class); + TYPE_MAP.put("getCurrentContextRequest", GetCurrentContextRequest.class); + TYPE_MAP.put("getInfoRequest", GetInfoRequest.class); + TYPE_MAP.put("getOrCreateChannelRequest", GetOrCreateChannelRequest.class); + TYPE_MAP.put("getUserChannelsRequest", GetUserChannelsRequest.class); + TYPE_MAP.put("heartbeatAcknowledgementRequest", HeartbeatAcknowledgementRequest.class); + TYPE_MAP.put("intentListenerUnsubscribeRequest", IntentListenerUnsubscribeRequest.class); + TYPE_MAP.put("intentResultRequest", IntentResultRequest.class); + TYPE_MAP.put("joinUserChannelRequest", JoinUserChannelRequest.class); + TYPE_MAP.put("leaveCurrentChannelRequest", LeaveCurrentChannelRequest.class); + TYPE_MAP.put("openRequest", OpenRequest.class); + TYPE_MAP.put("privateChannelAddEventListenerRequest", PrivateChannelAddEventListenerRequest.class); + TYPE_MAP.put("privateChannelDisconnectRequest", PrivateChannelDisconnectRequest.class); + TYPE_MAP.put("privateChannelUnsubscribeEventListenerRequest", PrivateChannelUnsubscribeEventListenerRequest.class); + TYPE_MAP.put("raiseIntentForContextRequest", RaiseIntentForContextRequest.class); + TYPE_MAP.put("raiseIntentRequest", RaiseIntentRequest.class); + + // Response messages + TYPE_MAP.put("addContextListenerResponse", AddContextListenerResponse.class); + TYPE_MAP.put("addEventListenerResponse", AddEventListenerResponse.class); + TYPE_MAP.put("addIntentListenerResponse", AddIntentListenerResponse.class); + TYPE_MAP.put("broadcastResponse", BroadcastResponse.class); + TYPE_MAP.put("clearContextResponse", ClearContextResponse.class); + TYPE_MAP.put("contextListenerUnsubscribeResponse", ContextListenerUnsubscribeResponse.class); + TYPE_MAP.put("createPrivateChannelResponse", CreatePrivateChannelResponse.class); + TYPE_MAP.put("eventListenerUnsubscribeResponse", EventListenerUnsubscribeResponse.class); + TYPE_MAP.put("findInstancesResponse", FindInstancesResponse.class); + TYPE_MAP.put("findIntentResponse", FindIntentResponse.class); + TYPE_MAP.put("findIntentsByContextResponse", FindIntentsByContextResponse.class); + TYPE_MAP.put("getCurrentChannelResponse", GetCurrentChannelResponse.class); + TYPE_MAP.put("getCurrentContextResponse", GetCurrentContextResponse.class); + TYPE_MAP.put("getInfoResponse", GetInfoResponse.class); + TYPE_MAP.put("getOrCreateChannelResponse", GetOrCreateChannelResponse.class); + TYPE_MAP.put("getUserChannelsResponse", GetUserChannelsResponse.class); + TYPE_MAP.put("intentListenerUnsubscribeResponse", IntentListenerUnsubscribeResponse.class); + TYPE_MAP.put("intentResultResponse", IntentResultResponse.class); + TYPE_MAP.put("joinUserChannelResponse", JoinUserChannelResponse.class); + TYPE_MAP.put("leaveCurrentChannelResponse", LeaveCurrentChannelResponse.class); + TYPE_MAP.put("openResponse", OpenResponse.class); + TYPE_MAP.put("privateChannelAddEventListenerResponse", PrivateChannelAddEventListenerResponse.class); + TYPE_MAP.put("privateChannelDisconnectResponse", PrivateChannelDisconnectResponse.class); + TYPE_MAP.put("privateChannelUnsubscribeEventListenerResponse", PrivateChannelUnsubscribeEventListenerResponse.class); + TYPE_MAP.put("raiseIntentForContextResponse", RaiseIntentForContextResponse.class); + TYPE_MAP.put("raiseIntentResponse", RaiseIntentResponse.class); + TYPE_MAP.put("raiseIntentResultResponse", RaiseIntentResultResponse.class); + + // Event messages + TYPE_MAP.put("broadcastEvent", BroadcastEvent.class); + TYPE_MAP.put("channelChangedEvent", ChannelChangedEvent.class); + TYPE_MAP.put("contextClearedEvent", ContextClearedEvent.class); + TYPE_MAP.put("heartbeatEvent", HeartbeatEvent.class); + TYPE_MAP.put("intentEvent", IntentEvent.class); + TYPE_MAP.put("privateChannelOnAddContextListenerEvent", PrivateChannelOnAddContextListenerEvent.class); + TYPE_MAP.put("privateChannelOnDisconnectEvent", PrivateChannelOnDisconnectEvent.class); + TYPE_MAP.put("privateChannelOnUnsubscribeEvent", PrivateChannelOnUnsubscribeEvent.class); + } + + /** + * Creates a new SchemaConverter with a default ObjectMapper configuration. + */ + public SchemaConverter() { + this.mapper = createObjectMapper(); + } + + /** + * Creates a new SchemaConverter with a custom ObjectMapper. + * + * @param mapper the ObjectMapper to use + */ + public SchemaConverter(ObjectMapper mapper) { + this.mapper = mapper; + } + + private static ObjectMapper createObjectMapper() { + ObjectMapper om = new ObjectMapper(); + om.registerModule(new JavaTimeModule()); + om.registerModule(new Jdk8Module()); + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + om.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + + // Register mix-ins to handle optional fields that should be omitted when null + NullHandlingMixin.registerAll(om); + + return om; + } + + /** + * Get the Java class for a given FDC3 message type string. + * + * @param messageType the FDC3 message type string (e.g., "broadcastRequest") + * @return the corresponding Java class, or null if not found + */ + public Class getClassForType(String messageType) { + return TYPE_MAP.get(messageType); + } + + /** + * Parse a JSON string and return the appropriate message object based on the "type" field. + * + * @param json the JSON string to parse + * @return the parsed message object + * @throws IOException if parsing fails + * @throws IllegalArgumentException if the type is unknown + */ + public Object fromJson(String json) throws IOException { + JsonNode node = mapper.readTree(json); + String type = node.has("type") ? node.get("type").asText() : null; + + if (type == null) { + throw new IllegalArgumentException("JSON does not contain a 'type' field"); + } + + Class clazz = TYPE_MAP.get(type); + if (clazz == null) { + throw new IllegalArgumentException("Unknown message type: " + type); + } + + return mapper.treeToValue(node, clazz); + } + + /** + * Parse a JSON string into a specific message class. + * + * @param json the JSON string to parse + * @param clazz the target class + * @param the type of the message + * @return the parsed message object + * @throws IOException if parsing fails + */ + public T fromJson(String json, Class clazz) throws IOException { + return mapper.readValue(json, clazz); + } + + /** + * Convert an object to another type (e.g., Map to typed object). + * + * @param fromValue the source object + * @param toValueType the target type + * @param the type to convert to + * @return the converted object + */ + public T convertValue(Object fromValue, Class toValueType) { + return mapper.convertValue(fromValue, toValueType); + } + + /** + * Convert an object to a Map. + * + * @param value the object to convert + * @return the object as a Map + */ + @SuppressWarnings("unchecked") + public Map toMap(Object value) { + return mapper.convertValue(value, Map.class); + } + + /** + * Serialize a message object to JSON. + * + * @param message the message object to serialize + * @return the JSON string + * @throws JsonProcessingException if serialization fails + */ + public String toJson(Object message) throws JsonProcessingException { + return mapper.writeValueAsString(message); + } + + /** + * Serialize a message object to pretty-printed JSON. + * + * @param message the message object to serialize + * @return the pretty-printed JSON string + * @throws JsonProcessingException if serialization fails + */ + public String toJsonPretty(Object message) throws JsonProcessingException { + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(message); + } + + /** + * Check if two JSON strings are semantically equivalent (same content, possibly different formatting). + * + * @param json1 first JSON string + * @param json2 second JSON string + * @return true if the JSON objects are equivalent + * @throws IOException if parsing fails + */ + public boolean jsonEquals(String json1, String json2) throws IOException { + JsonNode node1 = mapper.readTree(json1); + JsonNode node2 = mapper.readTree(json2); + return node1.equals(node2); + } + + /** + * Get the ObjectMapper used by this converter. + * + * @return the ObjectMapper instance + */ + public ObjectMapper getObjectMapper() { + return mapper; + } +} diff --git a/fdc3-schema/src/main/npm/package-lock.json b/fdc3-schema/src/main/npm/package-lock.json new file mode 100644 index 00000000..9e058dce --- /dev/null +++ b/fdc3-schema/src/main/npm/package-lock.json @@ -0,0 +1,1242 @@ +{ + "name": "fdc3-schema-codegen", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fdc3-schema-codegen", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-context": "3.0.0-alpha.5", + "@finos/fdc3-schema": "3.0.0-alpha.5", + "quicktype": "26.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@finos/fdc3-context": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-context/-/fdc3-context-3.0.0-alpha.5.tgz", + "integrity": "sha512-VN2LEmWvqLz4xsfXEsqcMNJjxD97/oyh7uPOwHmapoIuc0aW0YS9750tbcCf9GqC3XKnaca+itSW+rhlStJNvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@finos/fdc3-schema": { + "version": "3.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@finos/fdc3-schema/-/fdc3-schema-3.0.0-alpha.5.tgz", + "integrity": "sha512-LAKu4HEpQ+UNDco/1ehObiO+QqHoOmGFCP8dk5EerA/2XL0ki6bTFoM0E9ZaGeOQcxz9ifRAJrRDiiYzVi21Bg==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.4.0.tgz", + "integrity": "sha512-mDC+qosuNa4lxR3ioMBb6CD0XLRsQBplU+zRPUYiMLXKeVPZ6UYphdNG/EGReig0YyfnVlBKZEXl1wzTotYmPA==", + "license": "MIT" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", + "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/readable-stream": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", + "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/urijs": { + "version": "1.19.26", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", + "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "license": "Apache-2.0" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.4.tgz", + "integrity": "sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==", + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.1", + "typical": "^7.3.0" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.3.tgz", + "integrity": "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graphql": { + "version": "16.14.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz", + "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", + "integrity": "sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/path-equal": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.8.tgz", + "integrity": "sha512-rCJWMlXlk9lZ2FEllgvh2IgPj/kxMx2sOeqtFNLO8dxEY0I4hBTa+ZW3JAsgeiTe8vL4MifATVDwxF9nGUI7HQ==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/quicktype": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype/-/quicktype-26.0.0.tgz", + "integrity": "sha512-6sGRYEe3402KFTVKhqnsE6Z6Jdi5jryc/6cg+A8kx3dvIy01Ex35OcuuuZUZDbvzFw+1fkseCpLpbGhDS3uLJA==", + "license": "Apache-2.0", + "workspaces": [ + "./packages/quicktype-core", + "./packages/quicktype-graphql-input", + "./packages/quicktype-typescript-input", + "./packages/quicktype-vscode" + ], + "dependencies": { + "@glideapps/ts-necessities": "^2.2.3", + "@types/readable-stream": "4.0.10", + "chalk": "^4.1.2", + "collection-utils": "^1.0.1", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1", + "graphql": "^16.11.0", + "lodash": "^4.18.1", + "moment": "^2.30.1", + "quicktype-core": "26.0.0", + "quicktype-graphql-input": "26.0.0", + "quicktype-typescript-input": "26.0.0", + "readable-stream": "^4.5.2", + "stream-json": "3.5.0", + "string-to-stream": "^3.0.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "quicktype": "dist/index.js" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/quicktype-core": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-26.0.0.tgz", + "integrity": "sha512-tLSe2RkSj7c7ocTc+QMuQDGgEetGhZvKXLv1vNwpAQX2x8oOGYU9KSgJdIP9Qvy5hm47S2k3ZAX1LQAdS75JaA==", + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "@types/readable-stream": "4.0.10", + "@types/urijs": "^1.19.26", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "is-url": "^1.2.4", + "lodash": "^4.18.1", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.9.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/quicktype-core/node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "license": "MIT" + }, + "node_modules/quicktype-core/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/quicktype-graphql-input": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-graphql-input/-/quicktype-graphql-input-26.0.0.tgz", + "integrity": "sha512-bI129FVf6LLrG+6rh0gB9905oqNN0oGuZYIS0gV3V3C4JEdaR2qavdM/r925pUISwM3frrYE4McSDsuAzrHRTw==", + "license": "Apache-2.0", + "dependencies": { + "collection-utils": "^1.0.1", + "graphql": "^16.11.0", + "quicktype-core": "26.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/quicktype-typescript-input": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/quicktype-typescript-input/-/quicktype-typescript-input-26.0.0.tgz", + "integrity": "sha512-8Fo23bQ2yON2VdjIgPvzLx0nqaqjgUb/xIBcYjd0D4U5cWJ7oABLeNRH0krcSrFp9ez5qDPHB2xbkSLXNFaW9w==", + "license": "Apache-2.0", + "dependencies": { + "quicktype-core": "26.0.0", + "typescript": "5.9.3", + "typescript-json-schema": "0.67.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/stream-chain": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-4.2.5.tgz", + "integrity": "sha512-Wtyq3bNE3ggLR0v2vftqvuhltym3WbZAkZpfIrkr5F/6vpeUmWmwTgXa16zD87gpahwJ/Qulq3zVfUlgIc0J2A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/uhop" + } + }, + "node_modules/stream-json": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-3.5.0.tgz", + "integrity": "sha512-dobB7zipGW8o11PvdRljQSWuyMxifADLvoHeA4elwNWOTbZo6+BlNa+P6aCq7Y9jRiWTy2Ucu2xSv0Y2/T+/kQ==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^4.2.5" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/uhop" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string-to-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", + "integrity": "sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg==", + "license": "MIT", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/string-to-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.3.tgz", + "integrity": "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-json-schema": { + "version": "0.67.4", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.67.4.tgz", + "integrity": "sha512-BhDCVfwGtPKKt9JOBvh6ocmSbEk7ftx7dpqqIpvGNrjzYcUKm8pnYwKSFfNJwqcp/qNTfZr9sKtVyTxx4V9iRA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/json-schema": "^7.0.15", + "@types/node": "^24.10.2", + "glob": "^13.0.6", + "path-equal": "^1.2.5", + "safe-stable-stringify": "^2.5.0", + "ts-node": "^10.9.2", + "typescript": "~5.9.3", + "vm2": "^3.11.3", + "yargs": "^18.0.0" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/typescript-json-schema/node_modules/@types/node": { + "version": "24.13.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.6.tgz", + "integrity": "sha512-SGrw/h3KPFshy3OE6ZL53LMBG5vGQQ8/gIpiqz/kRZhPJ7HgwCEs8LBuNtWLa8dvGZVpSF7+Bf+c11HUrCb/yg==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/typescript-json-schema/node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, + "node_modules/vm2": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.12.2.tgz", + "integrity": "sha512-LRHt4xU6eXshlZEcSZVrTehLGxRDjHvjmFPGwEp4xGpZX61QzH6Xm9wK2nU7XAp36V1w2xILAL1LwxVkgD1Ipw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "acorn-walk": "^8.3.4" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/fdc3-schema/src/main/npm/package.json b/fdc3-schema/src/main/npm/package.json new file mode 100644 index 00000000..b95bd8e4 --- /dev/null +++ b/fdc3-schema/src/main/npm/package.json @@ -0,0 +1,12 @@ +{ + "name": "fdc3-schema-codegen", + "version": "1.0.0", + "private": true, + "description": "Pinned toolchain for generating Java types from the FDC3 API JSON schemas. Copied into target/npm-work by the Maven build, which then runs 'npm ci' against the committed lockfile.", + "license": "Apache-2.0", + "dependencies": { + "@finos/fdc3-context": "3.0.0-alpha.5", + "@finos/fdc3-schema": "3.0.0-alpha.5", + "quicktype": "26.0.0" + } +} diff --git a/fdc3-schema/src/main/schemas-overlay/api/README.md b/fdc3-schema/src/main/schemas-overlay/api/README.md new file mode 100644 index 00000000..a15f2fe0 --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/README.md @@ -0,0 +1,15 @@ +# API schema overlay + +The build downloads `@finos/fdc3-schema` from npm (see `fdc3.npm.version` in the root +`pom.xml`) and copies it into `target/schema-work`. The files in this directory are +then copied over the top, adding schemas that are not yet in a published release. + +This directory exists only for the WebSocket Connection Protocol (WSCP) schemas. +`fdc3-get-agent` generates types from these, and they are not in +`@finos/fdc3-schema@3.0.0-alpha.5` (or any earlier cut). When WSCP lands in a published +npm release, delete every file here, then remove this directory and the +`copy-api-overlay` executions in `fdc3-schema/pom.xml` and `fdc3-context/pom.xml`. + +Do not add DACP or other API schemas here — those come from npm unmodified. Schema +changes belong upstream in the [FDC3 repository](https://github.com/finos/FDC3), not +in this binding. diff --git a/fdc3-schema/src/main/schemas-overlay/api/WSCPApplicationConnect.schema.json b/fdc3-schema/src/main/schemas-overlay/api/WSCPApplicationConnect.schema.json new file mode 100644 index 00000000..e3fba650 --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/WSCPApplicationConnect.schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://fdc3.finos.org/schemas/next/api/WSCPApplicationConnect.schema.json", + "title": "WebSocket Connection Protocol Application Connect", + "description": "Connect message sent by a native application during the WSCP handshake. When the application is the TCP initiator it MUST include sharedSecret. When the application is the acceptor (responding to WSCPDesktopAgentConnect) it MUST NOT include sharedSecret.", + "type": "object", + "allOf": [ + { + "$ref": "#/$defs/WSCPApplicationConnectBase" + }, + { + "$ref": "WSCPConnectionStep.schema.json" + } + ], + "$defs": { + "WSCPApplicationConnectBase": { + "type": "object", + "properties": { + "type": { + "title": "WSCPApplicationConnect Message Type", + "const": "WSCPApplicationConnect" + }, + "payload": { + "title": "WSCPApplicationConnect Payload", + "type": "object", + "properties": { + "protocolVersion": { + "title": "Protocol version", + "description": "WSCP protocol version.", + "type": "string", + "const": "1.0" + }, + "sharedSecret": { + "title": "Shared secret", + "description": "Pairing credential scoped to a single (fdc3Session, appInstance) pair. MUST be included when the application is the TCP initiator. MUST NOT be included when the application is the acceptor.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["protocolVersion"] + }, + "meta": { + "$ref": "WSCPConnectionStep.schema.json#/$defs/ConnectionStepMeta" + } + }, + "required": ["type", "payload", "meta"], + "additionalProperties": false + } + } +} diff --git a/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectFailed.schema.json b/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectFailed.schema.json new file mode 100644 index 00000000..9422997c --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectFailed.schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://fdc3.finos.org/schemas/next/api/WSCPConnectFailed.schema.json", + "title": "WebSocket Connection Protocol Connect Failed", + "description": "Message sent by the acceptor if the WSCP handshake fails.", + "type": "object", + "allOf": [ + { + "$ref": "#/$defs/WSCPConnectFailedBase" + }, + { + "$ref": "WSCPConnectionStep.schema.json" + } + ], + "$defs": { + "WSCPConnectFailedBase": { + "type": "object", + "properties": { + "type": { + "title": "WSCPConnectFailed Message Type", + "const": "WSCPConnectFailed" + }, + "payload": { + "title": "WSCPConnectFailed Payload", + "type": "object", + "properties": { + "message": { + "title": "Connection failed message", + "description": "Human-readable description of why the handshake failed.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["message"] + }, + "meta": { + "$ref": "WSCPConnectionStep.schema.json#/$defs/ConnectionStepMeta" + } + }, + "required": ["type", "payload", "meta"], + "additionalProperties": false + } + } +} diff --git a/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectionStep.schema.json b/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectionStep.schema.json new file mode 100644 index 00000000..b2389f23 --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/WSCPConnectionStep.schema.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://fdc3.finos.org/schemas/next/api/WSCPConnectionStep.schema.json", + "title": "WebSocket Connection Protocol Message", + "type": "object", + "description": "A message used during the WebSocket connection flow between a native application and a Desktop Agent. Used for messages sent in either direction.", + "properties": { + "type": { + "title": "Connection Step Message type", + "type": "string", + "enum": [ + "WSCPApplicationConnect", + "WSCPDesktopAgentConnect", + "WSCPConnectFailed", + "WSCPGoodbye" + ], + "description": "Identifies the type of the WebSocket connection step message." + }, + "payload": { + "title": "Message payload", + "type": "object", + "description": "The message payload, containing data pertaining to this connection step.", + "additionalProperties": true + }, + "meta": { + "title": "Connection Step Metadata", + "description": "Metadata for a WebSocket Connection Protocol message.", + "oneOf": [ + { + "$ref": "#/$defs/DisconnectStepMeta" + }, + { + "$ref": "#/$defs/ConnectionStepMeta" + } + ] + } + }, + "required": [ + "type", + "meta" + ], + "additionalProperties": false, + "$defs": { + "ConnectionStepMeta": { + "type": "object", + "properties": { + "connectionAttemptUuid": { + "$ref": "common.schema.json#/$defs/ConnectionAttemptUuid" + }, + "timestamp": { + "$ref": "common.schema.json#/$defs/Timestamp" + } + }, + "required": [ + "timestamp", + "connectionAttemptUuid" + ], + "additionalProperties": false + }, + "DisconnectStepMeta": { + "type": "object", + "properties": { + "timestamp": { + "$ref": "common.schema.json#/$defs/Timestamp" + } + }, + "required": [ + "timestamp" + ], + "additionalProperties": false + } + } +} diff --git a/fdc3-schema/src/main/schemas-overlay/api/WSCPDesktopAgentConnect.schema.json b/fdc3-schema/src/main/schemas-overlay/api/WSCPDesktopAgentConnect.schema.json new file mode 100644 index 00000000..e4aeaf15 --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/WSCPDesktopAgentConnect.schema.json @@ -0,0 +1,55 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://fdc3.finos.org/schemas/next/api/WSCPDesktopAgentConnect.schema.json", + "title": "WebSocket Connection Protocol Desktop Agent Connect", + "description": "Connect message sent by a Desktop Agent during the WSCP handshake. When the Desktop Agent is the TCP initiator it MUST include sharedSecret. When the Desktop Agent is the acceptor (responding to WSCPApplicationConnect) it MUST NOT include sharedSecret.", + "type": "object", + "allOf": [ + { + "$ref": "#/$defs/WSCPDesktopAgentConnectBase" + }, + { + "$ref": "WSCPConnectionStep.schema.json" + } + ], + "$defs": { + "WSCPDesktopAgentConnectBase": { + "type": "object", + "properties": { + "type": { + "title": "WSCPDesktopAgentConnect Message Type", + "const": "WSCPDesktopAgentConnect" + }, + "payload": { + "title": "WSCPDesktopAgentConnect Payload", + "type": "object", + "properties": { + "protocolVersion": { + "title": "Protocol version", + "description": "WSCP protocol version.", + "type": "string", + "const": "1.0" + }, + "sharedSecret": { + "title": "Shared secret", + "description": "Pairing credential scoped to a single (fdc3Session, appInstance) pair. MUST be included when the Desktop Agent is the TCP initiator. MUST NOT be included when the Desktop Agent is the acceptor.", + "type": "string" + }, + "implementationMetadata": { + "title": "ImplementationMetadata", + "description": "Implementation metadata for the Desktop Agent, including the connecting application instance's appMetadata (MUST include at least appId and instanceId). Same shape as returned by fdc3.getInfo().", + "$ref": "api.schema.json#/definitions/ImplementationMetadata" + } + }, + "additionalProperties": false, + "required": ["protocolVersion", "implementationMetadata"] + }, + "meta": { + "$ref": "WSCPConnectionStep.schema.json#/$defs/ConnectionStepMeta" + } + }, + "required": ["type", "payload", "meta"], + "additionalProperties": false + } + } +} diff --git a/fdc3-schema/src/main/schemas-overlay/api/WSCPGoodbye.schema.json b/fdc3-schema/src/main/schemas-overlay/api/WSCPGoodbye.schema.json new file mode 100644 index 00000000..470d02b5 --- /dev/null +++ b/fdc3-schema/src/main/schemas-overlay/api/WSCPGoodbye.schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://fdc3.finos.org/schemas/next/api/WSCPGoodbye.schema.json", + "title": "WebSocket Connection Protocol Goodbye", + "description": "Goodbye message to be sent when disconnecting a WebSocket connection. The acceptor should close the connection after receiving this message but retain the sharedSecret mapping for the app instance so that a subsequent connect can resume the session.", + "type": "object", + "allOf": [ + { + "$ref": "#/$defs/WSCPGoodbyeBase" + }, + { + "$ref": "WSCPConnectionStep.schema.json" + } + ], + "$defs": { + "WSCPGoodbyeBase": { + "type": "object", + "properties": { + "type": { + "title": "WSCPGoodbye Message Type", + "const": "WSCPGoodbye" + }, + "meta": { + "$ref": "WSCPConnectionStep.schema.json#/$defs/DisconnectStepMeta" + } + }, + "required": ["type", "meta"], + "additionalProperties": false + } + } +} diff --git a/fdc3api/pom.xml b/fdc3-standard/pom.xml similarity index 51% rename from fdc3api/pom.xml rename to fdc3-standard/pom.xml index 7a7ee4ff..c44f616c 100644 --- a/fdc3api/pom.xml +++ b/fdc3-standard/pom.xml @@ -1,7 +1,7 @@ org.slf4j slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-jdk14 - ${slf4j.version} + com.fasterxml.jackson.core - jackson-core - ${jackson.version} + jackson-annotations + + - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} + org.junit.jupiter + junit-jupiter + test com.fasterxml.jackson.core jackson-databind - ${jackson.version} - - - - org.json - json - 20210307 - compile + test diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/DesktopAgent.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/DesktopAgent.java new file mode 100644 index 00000000..85e25ee7 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/DesktopAgent.java @@ -0,0 +1,822 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api; + +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.channel.PrivateChannel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; +import org.finos.fdc3.api.metadata.AppMetadata; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.ImplementationMetadata; +import org.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.IntentHandler; +import org.finos.fdc3.api.types.Listener; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletionStage; + +/** + * A Desktop Agent is a desktop component (or aggregate of components) that + * serves as a + * launcher and message router (broker) for applications in its domain. + * + * A Desktop Agent can be connected to one or more App Directories and will use + * directories for application + * identity and discovery. Typically, a Desktop Agent will contain the + * proprietary logic of + * a given platform, handling functionality like explicit application interop + * workflows where + * security, consistency, and implementation requirements are proprietary. + */ +public interface DesktopAgent { + /** + * Launches an app, specified via an `AppIdentifier` object. + * + * The `open` method differs in use from `raiseIntent`. Generally, it should be + * used when the target application is known but there is no specific intent. + * For example, if an application is querying the App Directory, `open` would be + * used to open an app returned in the search results. + * + * **Note**, if the intent, context and target app name are all known, it is + * recommended to instead use `raiseIntent` with the `target` argument. + * + * If a Context object is passed in, this object will be provided to the opened + * application via a contextListener. The Context argument is functionally + * equivalent to opening the target app with no context and broadcasting the + * context directly to it. + * + * Returns an `AppIdentifier` object with the `instanceId` field set identifying + * the instance of the application opened by this call. + * + * If an error occurs while opening the app, the promise MUST be rejected with + * an `Error` Object with a `message` chosen from the `OpenError` enumeration. + * + * ```javascript + * //Open an app without context, using an AppIdentifier object to specify the + * target by `appId`. + * let appIdentifier = {appId: 'myApp-v1.0.1'}; + * let instanceIdentifier = await fdc3.open(appIdentifier); + * + * //Open an app with context + * let instanceIdentifier = await fdc3.open(appIdentifier, context); + * ``` + */ + CompletionStage open(AppIdentifier app, Context context); + + CompletionStage open(AppIdentifier app, Context context, AppProvidableContextMetadata metadata); + + default CompletionStage open(AppIdentifier app) { + return open(app, null); + } + + /** + * Requests that the Desktop Agent close the calling application's window or frame. + * + * If the Desktop Agent cannot close the app, the promise MUST be rejected with an + * `Error` Object with a `message` chosen from the `CloseError` enumeration. + */ + CompletionStage close(); + + /** + * Find out more information about a particular intent by passing its name, and + * optionally its context and/or a desired result context type. + * + * `findIntent` is effectively granting programmatic access to the Desktop + * Agent's resolver. + * It returns a promise resolving to the intent, its metadata and metadata about + * the apps and app instances that registered that intent. + * This can be used to raise the intent against a specific app or app instance. + * + * If the resolution fails, the promise MUST be rejected with an `Error` Object + * with a `message` chosen from the `ResolveError` enumeration. This includes + * the case where no apps are found that resolve the intent, when the + * `ResolveError.NoAppsFound` message should be used. + * + * Result types may be a type name, the string "channel" (which indicates that + * the app + * will return a channel) or a string indicating a channel that returns a + * specific type, + * e.g. {@code channel}. + * + * If intent resolution to an app returning a channel is requested, the desktop + * agent + * MUST include both apps that are registered as returning a channel and those + * registered + * as returning a channel with a specific type in the response. + * + * ```javascript + * // I know 'StartChat' exists as a concept, and want to know which apps can + * resolve it ... + * const appIntent = await fdc3.findIntent("StartChat"); + * + * // returns a single AppIntent: + * // { + * // intent: { name: "StartChat", displayName: "Chat" }, + * // apps: [ + * // { appId: "Skype" }, + * // { appId: "Symphony" }, + * // { appId: "Slack" } + * // ] + * // } + * + * // raise the intent against a particular app + * await fdc3.raiseIntent(appIntent.intent.name, context, appIntent.apps[0]); + * + * //later, we want to raise 'StartChat' intent again + * const appIntent = await fdc3.findIntent("StartChat"); + * // returns an AppIntent, but with multiple options for resolution, + * // which includes an existing instance of an application: + * // { + * // intent: { name: "StartChat", displayName: "Chat" }, + * // apps: [ + * // { appId: "Skype" }, + * // { appId: "Symphony" }, + * // { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" }, + * // { appId: "Slack" } + * // ] + * ``` + * + * An optional input context object and result type may be specified, which the + * resolver MUST use to filter the returned applications such that each supports + * the specified input and result types. + * + * ```javascript + * const appIntent = await fdc3.findIntent("StartChat", contact); + * + * // returns only apps that support the type of the specified input context: + * // { + * // intent: { name: "StartChat", displayName: "Chat" }, + * // apps: [{ appId: "Symphony" }] + * // } + * + * const appIntent = await fdc3.findIntent("ViewContact", contact, + * "fdc3.ContactList"); + * + * // returns only apps that return the specified result Context type: + * // { + * // intent: { name: "ViewContact", displayName: "View Contact Details" }, + * // apps: { appId: "MyCRM", resultType: "fdc3.ContactList"}] + * // } + * + * const appIntent = await fdc3.findIntent("QuoteStream", instrument, + * "channel<fdc3.Quote>"); + * + * // returns only apps that return a channel which will receive the specified + * input and result types: + * // { + * // intent: { name: "QuoteStream", displayName: "Quotes stream" }, + * // apps: [{ appId: "MyOMS", resultType: "channel<fdc3.Quote>"}] + * // } + * ``` + */ + CompletionStage findIntent(String intent, Context context, String resultType); + + default CompletionStage findIntent(String intent, Context context) { + return findIntent(intent, context, null); + } + + default CompletionStage findIntent(String intent) { + return findIntent(intent, null); + } + + /** + * Find all the available intents for a particular context, and optionally a + * desired result context type. + * + * `findIntentsByContext` is effectively granting programmatic access to the + * Desktop Agent's resolver. + * It returns a promise resolving to an `AppIntent` which provides details of + * the intent, its metadata and metadata about the apps and app instances that + * are registered to handle it. This can be used to raise the intent against a + * specific app or app instance. + * + * If the resolution fails, the promise MUST be rejected with an `Error` Object + * with a `message` chosen from the `ResolveError` enumeration. This includes + * the case where no intents with associated apps are found, when the + * `ResolveError.NoAppsFound` message should be used. + * + * The optional `resultType` argument may be a type name, the string "channel" + * (which indicates that the app + * should return a channel) or a string indicating a channel that returns a + * specific type, + * e.g. {@code channel}. If intent resolution to an app returning a + * channel is requested without + * a specified context type, the desktop agent MUST also include apps that are + * registered as returning a + * channel with a specific type in the response. + * + * ```javascript + * // I have a context object, and I want to know what I can do with it, hence, + * I look for intents and apps to resolve them... + * const appIntents = await fdc3.findIntentsByContext(context); + * + * // returns for example: + * // [ + * // { + * // intent: { name: "StartCall", displayName: "Call" }, + * // apps: [{ name: "Skype" }] + * // }, + * // { + * // intent: { name: "StartChat", displayName: "Chat" }, + * // apps: [ + * // { appId: "Skype" }, + * // { appId: "Symphony" }, + * // { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" }, + * // { appId: "Slack" } + * // ] + * // } + * // ]; + * + * // or I look for only intents that are resolved by apps returning a + * particular result type + * const appIntentsForType = await fdc3.findIntentsByContext(context, + * "fdc3.ContactList"); + * // returns for example: + * // [{ + * // intent: { name: "ViewContact", displayName: "View Contacts" }, + * // apps: [{ appId: "MyCRM", resultType: "fdc3.ContactList"}] + * // }]; + * + * // select a particular intent to raise + * const resolvedIntent = appIntents[1]; + * + * // target a particular app or instance + * const selectedApp = resolvedIntent.apps[2]; + * + * // raise the intent, passing the given context, targeting the app or app + * instance + * await fdc3.raiseIntent(startChat.intent.name, context, selectedApp); + * ``` + */ + CompletionStage> findIntentsByContext(Context context, String resultType); + + default CompletionStage> findIntentsByContext(Context context) { + return findIntentsByContext(context, null); + } + + /** + * Find all the available instances for a particular application. + * + * If there are no instances of the specified application the returned promise + * should resolve to an empty array. + * + * If the request fails for another reason, the promise MUST be rejected with an + * `Error` Object with a `message` chosen from the `ResolveError` enumeration. + * + * ```javascript + * // Retrieve a list of instances of an application + * let instances = await fdc3.findInstances({appId: "MyAppId"}); + * + * // Target a raised intent at a specific instance + * let resolution = fdc3.raiseIntent("ViewInstrument", context, instances[0]); + * ``` + * + * @param app + */ + CompletionStage> findInstances(AppIdentifier app); + + /** + * Publishes context to other apps on the desktop. Calling `broadcast` at the + * `DesktopAgent` scope will push the context to whatever _User Channel_ the app + * is joined to. If the app is not currently joined to a channel, calling + * `fdc3.broadcast` will have no effect. Apps can still directly broadcast and + * listen to context on any channel via the methods on the `Channel` class. + * + * DesktopAgent implementations should ensure that context messages broadcast to + * a channel by an application joined to it should not be delivered back to that + * same application. + * + * If you are working with complex context types composed of other simpler types + * then you should broadcast + * each individual type (starting with the simpler types, followed by the + * complex type) that you want other + * apps to be able to respond to. Doing so allows applications to filter the + * context types they receive by + * adding listeners for specific context types. + * + * ```javascript + * const instrument = { + * type: 'fdc3.instrument', + * id: { + * ticker: 'AAPL' + * } + * }; + * fdc3.broadcast(context); + * ``` + */ + CompletionStage broadcast(Context context); + + CompletionStage broadcast(Context context, AppProvidableContextMetadata metadata); + + /** + * Raises a specific intent for resolution against apps registered with the + * desktop agent. + * + * The desktop agent MUST resolve the correct app to target based on the + * provided intent name and context data. If multiple matching apps are found, + * the user MAY be presented with a Resolver UI allowing them to pick one, or + * another method of Resolution applied to select an app. + * Alternatively, the specific app or app instance to target can also be + * provided. A list of valid target applications and instances can be retrieved + * via `findIntent`. + * + * If a target app for the intent cannot be found with the criteria provided or + * the user either closes the resolver UI or otherwise cancels resolution, the + * promise MUST be rejected with an `Error` object with a `message` chosen from + * the `ResolveError` enumeration. If a specific target `app` parameter was set, + * but either the app or app instance is not available, the promise MUST be + * rejected with an `Error` object with either the + * `ResolveError.TargetAppUnavailable` or + * `ResolveError.TargetInstanceUnavailable` string as its `message`. + * + * If you wish to raise an Intent without a context, use the `fdc3.nothing` + * context type. This type exists so that apps can explicitly declare support + * for raising an intent without context. + * + * Returns an `IntentResolution` object with details of the app instance that + * was selected (or started) to respond to the intent. + * + * Issuing apps may optionally wait on the promise that is returned by the + * `getResult()` member of the `IntentResolution`. This promise will resolve + * when the _receiving app's_ intent handler function returns and resolves a + * promise. The Desktop Agent resolves the issuing app's promise with the + * Context object or Channel that is provided as resolution within the receiving + * app. The Desktop Agent MUST reject the issuing app's promise, with a string + * from the `ResultError` enumeration, if: (1) the intent handling function's + * returned promise rejects, (2) the intent handling function doesn't return a + * promise, or (3) the returned promise resolves to an invalid type. + * + * ```javascript + * // raise an intent for resolution by the desktop agent + * // a resolver UI may be displayed if more than one application can resolve + * the intent + * await fdc3.raiseIntent("StartChat", context); + * + * // or find apps to resolve an intent to start a chat with a given contact + * const appIntent = await fdc3.findIntent("StartChat", context); + * // use the metadata of an app or app instance to describe the target app for + * the intent + * await fdc3.raiseIntent("StartChat", context, appIntent.apps[0]); + * + * //Raise an intent without a context by using the null context type + * await fdc3.raiseIntent("StartChat", {type: "fdc3.nothing"}); + * + * //Raise an intent and retrieve a result from the IntentResolution + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { //detect whether the result is Context or a + * Channel + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return anything` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * ``` + */ + /** + * @param intent the name of the intent to raise + * @param context the context to send with the intent + * @param app the app or app instance to target, or null to let the agent resolve + * @param newInstance true to require a new instance of the target app, or null for the + * agent's default behaviour + * @param metadata optional metadata to pass to the receiving app + */ + CompletionStage raiseIntent(String intent, Context context, AppIdentifier app, + Boolean newInstance, AppProvidableContextMetadata metadata); + + default CompletionStage raiseIntent(String intent) { + return raiseIntent(intent, null, null, null, null); + } + + default CompletionStage raiseIntent(String intent, Context context) { + return raiseIntent(intent, context, null, null, null); + } + + default CompletionStage raiseIntent(String intent, Context context, AppIdentifier app) { + return raiseIntent(intent, context, app, null, null); + } + + default CompletionStage raiseIntent(String intent, Context context, AppIdentifier app, + Boolean newInstance) { + return raiseIntent(intent, context, app, newInstance, null); + } + + /** + * Finds and raises an intent against apps registered with the desktop agent + * based on the type of the specified context data example. + * + * The desktop agent SHOULD first resolve to a specific intent based on the + * provided context if more than one intent is available for the specified + * context. This MAY be achieved by displaying a resolver UI. It SHOULD then + * resolve to a specific app to handle the selected intent and specified + * context. + * Alternatively, the specific app or app instance to target can also be + * provided, in which case the resolver SHOULD only offer intents supported by + * the specified application. + * + * Using `raiseIntentForContext` is similar to calling `findIntentsByContext`, + * and then raising an intent against one of the returned apps, except in this + * case the desktop agent has the opportunity to provide the user with a richer + * selection interface where they can choose both the intent and target app. + * + * Returns an `IntentResolution` object, see `raiseIntent()` for details. + * + * If a target intent and app cannot be found with the criteria provided or the + * user either closes the resolver UI or otherwise cancels resolution, the + * promise MUST be rejected with an `Error` object with a `message` chosen from + * the `ResolveError` enumeration. If a specific target `app` parameter was set, + * but either the app or app instance is not available, the promise MUST be + * rejected with an `Error` object with either the + * `ResolveError.TargetAppUnavailable` or + * `ResolveError.TargetInstanceUnavailable` string as its `message`. + * + * ```javascript + * // Resolve against all intents registered for the type of the specified + * context + * await fdc3.raiseIntentForContext(context); + * + * // Resolve against all intents registered by a specific target app for the + * specified context + * await fdc3.raiseIntentForContext(context, targetAppIdentifier); + * ``` + */ + /** + * @param context the context whose type is used to resolve candidate intents + * @param app the app or app instance to target, or null to let the agent resolve + * @param newInstance true to require a new instance of the target app, or null for the + * agent's default behaviour + * @param metadata optional metadata to pass to the receiving app + */ + CompletionStage raiseIntentForContext(Context context, AppIdentifier app, + Boolean newInstance, AppProvidableContextMetadata metadata); + + default CompletionStage raiseIntentForContext(Context context) { + return raiseIntentForContext(context, null, null, null); + } + + default CompletionStage raiseIntentForContext(Context context, AppIdentifier app) { + return raiseIntentForContext(context, app, null, null); + } + + default CompletionStage raiseIntentForContext(Context context, AppIdentifier app, + Boolean newInstance) { + return raiseIntentForContext(context, app, newInstance, null); + } + + /** + * Adds a listener for incoming Intents from the Agent. The handler function may + * return void or a promise that should resolve to an `IntentResult`, which is + * either a `Context` object, representing any data that should be returned, or + * a `Channel` over which data responses will be sent. The IntentResult will be + * returned to app that raised the intent via the `IntentResolution` and + * retrieved from it using the `getResult()` function. + * + * The Desktop Agent MUST reject the promise returned by the `getResult()` + * function of `IntentResolution` if: (1) the intent handling function's + * returned promise rejects, (2) the intent handling function doesn't return a + * promise, or (3) the returned promise resolves to an invalid type. + * + * The `PrivateChannel` type is provided to support synchronisation of data + * transmitted over returned channels, by allowing both parties to listen for + * events denoting subscription and unsubscription from the returned channel. + * `PrivateChannels` are only retrievable via raising an intent. + * + * Optional metadata about the raised intent, including the app that originated + * the message, SHOULD be provided by the desktop agent implementation. + * + * ```javascript + * //Handle a raised intent + * const listener = fdc3.addIntentListener('StartChat', context => { + * // start chat has been requested by another application + * return; + * }); + * + * //Handle a raised intent and log the originating app metadata + * const listener = fdc3.addIntentListener('StartChat', (contact, metadata) => { + * console.log(`Received intent StartChat\nContext: ${contact}\nOriginating app: + * ${metadata?.source}`); + * return; + * }); + * + * //Handle a raised intent and return Context data via a promise + * fdc3.addIntentListener("CreateOrder", (context) => { + * return new Promise<Context>((resolve) => { + * // go create the order + * resolve({type: "fdc3.order", id: { "orderId": 1234}}); + * }); + * }); + * + * //Handle a raised intent and return a Private Channel over which response + * will be sent + * fdc3.addIntentListener("QuoteStream", async (context) => { + * const channel: PrivateChannel = await fdc3.createPrivateChannel(); + * const symbol = context.id.symbol; + * + * // Called when the remote side adds a context listener + * const addContextListener = await channel.addEventListener("addContextListener", + * (event) => { + * // broadcast price quotes as they come in from our quote feed + * feed.onQuote(symbol, (price) => { + * channel.broadcast({ type: "price", price}); + * }); + * }); + * + * // Stop the feed if the remote side closes + * const disconnectListener = await channel.addEventListener("disconnect", () => { + * feed.stop(symbol); + * }); + * + * return channel; + * }); + * ``` + */ + CompletionStage addIntentListener(String intent, IntentHandler handler); + + CompletionStage addIntentListenerWithContext(String intent, String contextType, IntentHandler handler); + + CompletionStage addIntentListenerWithContext( + String intent, List contextTypes, IntentHandler handler); + + /** + * Adds a listener for incoming context broadcasts from the Desktop Agent via + * User channels. If the consumer is only interested in a context of a + * particular type, they can they can specify that type. If the consumer is able + * to receive context of any type or will inspect types received, then they can + * pass `null` as the `contextType` parameter to receive all context types. + * + * Context broadcasts are only received from apps that are joined to the same + * User channel as the listening application, hence, if the application is not + * currently joined to a channel no broadcasts will be received. If this + * function is called after the app has already joined a channel and the channel + * already contains context that would be passed to the context listener, then + * it will be called immediately with that context. + * + * Optional metadata about the context message, including the app that + * originated the message, SHOULD be provided by the desktop agent + * implementation. + * + * ```javascript + * // any context + * const listener = await fdc3.addContextListener(null, context => { ... }); + * + * // listener for a specific type + * const contactListener = await fdc3.addContextListener('fdc3.contact', contact + * => { ... }); + * + * // listener that logs metadata for the message a specific type + * const contactListener = await fdc3.addContextListener('fdc3.contact', + * (contact, metadata) => { + * console.log(`Received context message\nContext: ${contact}\nOriginating app: + * ${metadata?.source}`); + * //do something else with the context + * }); + * ``` + */ + CompletionStage addContextListener(String contextType, ContextHandler handler); + + /** + * Adds a listener for incoming contexts matching any of the specified context types. + */ + CompletionStage addContextListener(java.util.List contextTypes, ContextHandler handler); + + /** + * Registers a handler for non-context and non-intent events from the Desktop + * Agent. + * If the consumer is only interested in an event of a particular type, they can + * specify that type. + * If the consumer is able to receive events of any type or will inspect types + * received, + * then they can pass `null` as the `type` parameter to receive all event types. + * + * Whenever the handler function is called it will be passed an event object + * with details + * related to the event. + * + * ```javascript + * // listener for all events + * const listener = await fdc3.addEventListener(null, event => { ... }); + * + * // listener for a specific event type + * const channelChangedListener = await + * fdc3.addEventListener('userChannelChanged', event => { ... }); + * ``` + * + * @param type the type of event to listen for (e.g., "userChannelChanged"), + * or null to receive all event types + * @param handler the handler function to be called when matching events occur + * @return a Listener object that can be used to unsubscribe from the events + */ + CompletionStage addEventListener(String type, EventHandler handler); + + /** + * Retrieves a list of the User channels available for the app to join. + */ + CompletionStage> getUserChannels(); + + /** + * Optional function that joins the app to the specified User channel. In most + * cases, applications SHOULD be joined to channels via UX provided to the + * application by the desktop agent, rather than calling this function directly. + * + * If an app is joined to a channel, all `fdc3.broadcast` calls will go to the + * channel, and all listeners assigned via `fdc3.addContextListener` will listen + * on the channel. + * + * If the channel already contains context that would be passed to context + * listeners assed via `fdc3.addContextListener` then those listeners will be + * called immediately with that context. + * + * An app can only be joined to one channel at a time. + * + * If an error occurs (such as the channel is unavailable or the join request is + * denied) the promise MUST be rejected with an `Error` Object with a `message` + * chosen from the `ChannelError` enumeration. + * + * ```javascript + * // get all system channels + * const channels = await fdc3.getUserChannels(); + * // create UI to pick from the User channels + * // join the channel on selection + * fdc3.joinUserChannel(selectedChannel.id); + * ``` + */ + CompletionStage joinUserChannel(String channelId); + + /** + * Returns a `Channel` object for the specified channel, creating it (as an + * _App_ channel) if it does not exist. + * + * If the Channel cannot be created or access was denied, the returned promise + * MUST be rejected with an `Error` Object with a `message` chosen from the + * `ChannelError` enumeration. + * + * ```javascript + * try { + * const myChannel = await fdc3.getOrCreateChannel("myChannel"); + * const myChannel.addContextListener(null, context => {}); + * } + * catch (err){ + * //app could not register the channel + * } + * ``` + */ + CompletionStage getOrCreateChannel(String channelId); + + /** + * Returns a `Channel` with an auto-generated identity that is intended for + * private communication between applications. Primarily used to create Channels + * that will be returned to other applications via an `IntentResolution` for a + * raised intent. + * + * If the `PrivateChannel` cannot be created, the returned promise MUST be + * rejected with an `Error` object with a `message` chosen from the + * `ChannelError` enumeration. + * + * The `PrivateChannel` type is provided to support synchronisation of data + * transmitted over returned channels, by allowing both parties to listen for + * events denoting subscription and unsubscription from the returned channel. + * `PrivateChannels` are only retrievable via raising an intent. + * + * * It is intended that Desktop Agent implementations: + * - SHOULD restrict external apps from listening or publishing on this channel. + * - MUST prevent `PrivateChannels` from being retrieved via + * fdc3.getOrCreateChannel. + * - MUST provide the `id` value for the channel as required by the `Channel` + * interface. + * + * ```javascript + * fdc3.addIntentListener("QuoteStream", async (context) => { + * const channel: PrivateChannel = await fdc3.createPrivateChannel(); + * const symbol = context.id.ticker; + * + * // This gets called when the remote side adds a context listener + * const addContextListener = await channel.addEventListener("addContextListener", + * (event) => { + * // broadcast price quotes as they come in from our quote feed + * feed.onQuote(symbol, (price) => { + * channel.broadcast({ type: "price", price}); + * }); + * }); + * + * // This gets called when the remote side calls Listener.unsubscribe() + * const unsubscriberListener = await channel.addEventListener("unsubscribe", + * (event) => { + * feed.stop(symbol); + * }); + * + * // This gets called if the remote side closes + * const disconnectListener = await channel.addEventListener("disconnect", () => { + * feed.stop(symbol); + * }) + * + * return channel; + * }); + * ``` + */ + CompletionStage createPrivateChannel(); + + /** + * Optional function that returns the {@code Channel} object for the current User channel + * membership. In most cases an application's membership of channels SHOULD be managed + * through UX provided to the application by the Desktop Agent, rather than by calling this + * function directly. + * + * @return an empty {@code Optional} if the app is not joined to a User channel, otherwise + * the channel it is joined to + */ + CompletionStage> getCurrentChannel(); + + /** + * Optional function that removes the app from any User channel membership. In + * most cases, an application's membership of channels SHOULD be managed via UX + * provided to the application by the desktop agent, rather than calling this + * function directly. + * + * Context broadcast and listening through the top-level `fdc3.broadcast` and + * `fdc3.addContextListener` will be a no-op when the app is not on a channel. + * + * ```javascript + * //desktop-agent scope context listener + * const fdc3Listener = fdc3.addContextListener(null, context => {}); + * await fdc3.leaveCurrentChannel(); + * //the fdc3Listener will now cease receiving context + * //listening on a specific channel, retrieved via fdc3.getOrCreateChannel(), + * will continue to work: + * redChannel.addContextListener(null, channelListener); + * ``` + */ + CompletionStage leaveCurrentChannel(); + + /** + * Retrieves information about the FDC3 Desktop Agent implementation, including + * the supported version + * of the FDC3 specification, the name of the provider of the implementation, + * its own version number + * and the metadata of the calling application according to the desktop agent. + * + * Returns an `ImplementationMetadata` object. This metadata object can be used + * to vary the behavior + * of an application based on the version supported by the Desktop Agent and for + * logging purposes. + * + * ```js + * import {compareVersionNumbers, versionIsAtLeast} from '@finos/fdc3'; + * + * if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), "1.2")) { + * await fdc3.raiseIntentForContext(context); + * } else { + * await fdc3.raiseIntent("ViewChart", context); + * } + * ``` + * + * The `ImplementationMetadata` object returned also includes the metadata for + * the calling application, + * according to the Desktop Agent. This allows the application to retrieve its + * own `appId`, `instanceId` + * and other details, e.g.: + * + * ```js + * let implementationMetadata = await fdc3.getInfo(); + * let {appId, instanceId} = implementationMetadata.appMetadata; + * ``` + */ + CompletionStage getInfo(); + + /** + * Retrieves the `AppMetadata` for an `AppIdentifier`, which provides additional + * metadata (such as icons, + * a title and description) from the App Directory record for the application, + * that may be used for display + * purposes. + * + * ```js + * let appIdentifier = { appId: "MyAppId@my.appd.com" } + * let appMetadata = await fdc3.getAppMetadata(appIdentifier); + * ``` + */ + CompletionStage getAppMetadata(AppIdentifier app); +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/channel/Channel.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/channel/Channel.java similarity index 62% rename from fdc3api/src/main/java/com/finos/fdc3/api/channel/Channel.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/channel/Channel.java index e31aea9e..71eba7cc 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/channel/Channel.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/channel/Channel.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,20 @@ * limitations under the License. */ -package com.finos.fdc3.api.channel; +package org.finos.fdc3.api.channel; +import java.util.List; import java.util.Optional; import java.util.concurrent.CompletionStage; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.DisplayMetadata; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.api.types.IntentResult; -import com.finos.fdc3.api.types.Listener; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppProvidableContextMetadata; +import org.finos.fdc3.api.metadata.DisplayMetadata; +import org.finos.fdc3.api.types.ContextHandler; +import org.finos.fdc3.api.types.ContextWithMetadata; +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.api.types.Listener; /** * Object representing a context channel. @@ -39,9 +43,25 @@ public interface Channel extends IntentResult { * Can be "user", "app" or "private". */ enum Type { - User, - App, - Private, + User("user"), + App("app"), + Private("private"); + + private final String value; + + Type(String value) { + this.value = value; + } + + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } } Type getType(); @@ -50,7 +70,7 @@ enum Type { * Channels may be visualized and selectable by users. DisplayMetadata may be used to provide hints on how to see them. * For App channels, displayMetadata would typically not be present. */ - Optional displayMetadata(); + DisplayMetadata getDisplayMetadata(); /** * Broadcasts a context on the channel. This function can be used without first joining the channel, allowing applications to broadcast on both App Channels and User Channels that they aren't a member of. @@ -63,6 +83,8 @@ enum Type { */ CompletionStage broadcast(Context context); + CompletionStage broadcast(Context context, AppProvidableContextMetadata metadata); + /** * When a `contextType`_` is provided, the most recent context matching the type will be returned, or `null` if no matching context is found. * @@ -76,6 +98,33 @@ enum Type { CompletionStage> getCurrentContext(String contextType); + /** + * Returns the most recent context on the channel along with its metadata, or empty if none. + */ + default CompletionStage> getCurrentContextWithMetadata() { + return getCurrentContextWithMetadata(null); + } + + CompletionStage> getCurrentContextWithMetadata(String contextType); + + /** + * Clears context from the channel and fires the `contextCleared` event, notifying existing + * listeners that the context was cleared. Listeners added afterwards, and calls to + * `getCurrentContext`, will not receive any existing context until new context is broadcast + * to the channel. + * + * If a `contextType` is provided, only contexts of that type are cleared. If it is null, all + * contexts are cleared. + * + * @param contextType the context type to clear, or null to clear every type + */ + CompletionStage clearContext(String contextType); + + /** Clears every context type from the channel. */ + default CompletionStage clearContext() { + return clearContext(null); + } + /** * Adds a listener for incoming contexts of the specified _context type_ whenever a broadcast happens on this channel. * @@ -84,4 +133,17 @@ enum Type { * Optional metadata about each context message received, including the app that originated the message, SHOULD be provided by the desktop agent implementation. */ CompletionStage addContextListener(String contextType, ContextHandler handler); + + /** + * Adds a listener for incoming contexts matching any of the specified context types + * whenever a broadcast happens on this channel. + */ + CompletionStage addContextListener(List contextTypes, ContextHandler handler); + + /** + * Register a handler for events from the Channel. Whenever the handler function + * is called it will be passed an event object with details related to the event. + */ + CompletionStage addEventListener(String type, EventHandler handler); + } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/channel/PrivateChannel.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/channel/PrivateChannel.java new file mode 100644 index 00000000..fac30df7 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/channel/PrivateChannel.java @@ -0,0 +1,76 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.channel; + +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.types.EventHandler; +import org.finos.fdc3.api.types.Listener; + +/** + * Object representing a private context channel, which is intended to support secure communication between applications, and + * extends the Channel interface with event handlers which provide information on the connection state of both parties, ensuring + * that desktop agents do not need to queue or retain messages that are broadcast before a context listener is added and that + * applications are able to stop broadcasting messages when the other party has disconnected. It is intended that Desktop Agent + * implementations: - SHOULD restrict external apps from listening or publishing on this channel. - MUST prevent private channels + * from being retrieved via fdc3.getOrCreateChannel. - MUST provide the `id` value for the channel as required by the Channel + * interface. + */ +public interface PrivateChannel extends Channel { + /** + * Register a handler for events from the PrivateChannel. Whenever the handler function + * is called it will be passed an event object with details related to the event. + * + *
+     * // any event type
+     * Listener listener = myPrivateChannel.addEventListener(null, event -> {
+     *   System.out.println("Received event " + event.getType() + "\n\tDetails: " + event.getDetails());
+     * }).toCompletableFuture().join();
+     * 
+     * // listener for a specific event type
+     * Listener channelChangedListener = myPrivateChannel.addEventListener(
+     *    org.finos.fdc3.api.types.FDC3Event.Type.ADD_CONTEXT_LISTENER.getValue(),
+     *    event -> { ... }
+     * ).toCompletableFuture().join();
+     * 
+ * + * @param type If non-null, only events of the specified type will be received by the handler. + * Valid types are {@link org.finos.fdc3.api.types.FDC3Event.Type#ADD_CONTEXT_LISTENER}, + * {@link org.finos.fdc3.api.types.FDC3Event.Type#ON_UNSUBSCRIBE}, + * {@link org.finos.fdc3.api.types.FDC3Event.Type#ON_DISCONNECT}, + * or null for all events (string values: "addContextListener", "unsubscribe", "disconnect"). + * @param handler A function that events received will be passed to. + * @return A CompletionStage that resolves to a Listener object when the listener is successfully registered. + */ + CompletionStage addEventListener(String type, EventHandler handler); + + /** + * May be called to indicate that a participant will no longer interact with this channel. After this function has been called, + * Desktop Agents SHOULD prevent apps from broadcasting on this channel and MUST automatically call Listener.unsubscribe() for + * each listener that they've added (causing any "unsubscribe" event handler added by the other party to fire) before triggering + * any "disconnect" event handler added by the other party. + * + * @return a CompletionStage that completes when the disconnect has been acknowledged by the Desktop Agent + */ + CompletionStage disconnect(); + + @Override + default Type getType() { + + return Type.Private; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/context/Context.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/context/Context.java new file mode 100644 index 00000000..c9c7b17b --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/context/Context.java @@ -0,0 +1,125 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.context; + +import java.util.HashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.IntentResult; + +/** + * The base FDC3 Context type. + *

+ * The {@code fdc3.context} type defines the basic contract, or "shape", for all data exchanged + * by FDC3 operations. It is not usually used on its own: more specific type definitions, + * standardized or custom, build on it to provide the structure and properties shared by all + * FDC3 context data types. + *

+ * This implementation extends {@link HashMap} rather than declaring fixed fields, which means + * it: + *

    + *
  • preserves every field through serialization and deserialization, including properties + * this version of the API does not know about, so no data is lost in transit;
  • + *
  • accepts any context type, including custom ones;
  • + *
  • can be used directly as a {@code Map}.
  • + *
+ *

+ * To work with a context as a typed object, use the converter in the {@code fdc3-context} + * module, which maps between a {@code Context} and the generated type for its + * {@code type} value. + */ +public class Context extends HashMap implements IntentResult { + + public Context() { + } + + public Context(String type) { + setType(type); + } + + public Context(String type, String name) { + setType(type); + setName(name); + } + + public Context(String type, String name, Map id) { + setType(type); + setName(name); + setId(id); + } + + /** + * The type property is the only required part of the FDC3 context data schema. + * The FDC3 API relies on the `type` property being present to route shared context data appropriately. + */ + public String getType() { + return (String) get("type"); + } + + public void setType(String type) { + put("type", type); + } + + /** + * Context data objects may include a name property that can be used for more information, + * or display purposes. + */ + public String getName() { + return (String) get("name"); + } + + public void setName(String name) { + if (name != null) { + put("name", name); + } else { + remove("name"); + } + } + + /** + * Context data objects may include a set of equivalent key-value pairs that can be used to + * help applications identify and look up the context type they receive in their own domain. + */ + @SuppressWarnings("unchecked") + public Map getId() { + return (Map) get("id"); + } + + public void setId(Map id) { + if (id != null) { + put("id", id); + } else { + remove("id"); + } + } + + /** + * Create a Context from a Map. + * This is a convenience factory method for converting Map data to a Context object. + * + * @param map the map containing context data + * @return a new Context containing all entries from the map + */ + public static Context fromMap(Map map) { + if (map == null) { + return null; + } + Context context = new Context(); + context.putAll(map); + return context; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/AgentError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/AgentError.java new file mode 100644 index 00000000..1cdef516 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/AgentError.java @@ -0,0 +1,91 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when trying to connect to a Desktop Agent. + */ +public enum AgentError { + + /** + * Returned if no Desktop Agent was found by any means available, or if an agent previously + * connected to is not contactable on a subsequent connection attempt. + */ + AgentNotFound("AgentNotFound"), + + /** + * Returned if validation of the app identity by the Desktop Agent failed, or the app is not + * being allowed to connect for another reason. + */ + AccessDenied("AccessDenied"), + + /** + * Returned if an error or exception occurs while trying to set up communication with a + * Desktop Agent. + */ + ErrorOnConnect("ErrorOnConnect"), + + /** + * Returned if the failover function is not a function, or it did not resolve to one of the + * allowed types. + */ + InvalidFailover("InvalidFailover"), + + /** + * Returned if an API call rejects after a timeout, where the call is not aligned to another + * error enumeration. + */ + ApiTimeout("ApiTimeout"); + + private final String value; + + AgentError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static AgentError fromValue(String value) { + for (AgentError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown AgentError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ChannelError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ChannelError.java new file mode 100644 index 00000000..7b25fc1b --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ChannelError.java @@ -0,0 +1,91 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when calling channel-related methods. + */ +public enum ChannelError { + + /** + * Returned if the specified channel is not found when attempting to join a channel via + * {@code joinUserChannel}. + */ + NoChannelFound("NoChannelFound"), + + /** + * Should be returned when a request to join a user channel, or to retrieve a Channel object + * via {@code joinUserChannel} or {@code getOrCreateChannel}, is denied. + */ + AccessDenied("AccessDenied"), + + /** + * Should be returned when a channel cannot be created or retrieved via + * {@code getOrCreateChannel}. + */ + CreationFailed("CreationFailed"), + + /** + * Returned if a call to {@code broadcast} is made with an invalid context argument. Contexts + * should be objects with at least a {@code type} field that has a string value. + */ + MalformedContext("MalformedContext"), + + /** Returned if a timeout occurs before any channel-related API call is resolved. */ + ApiTimeout("ApiTimeout"), + + /** Returned when incorrect arguments are passed to API calls. */ + InvalidArguments("InvalidArguments"); + + private final String value; + + ChannelError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static ChannelError fromValue(String value) { + for (ChannelError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown ChannelError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/CloseError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/CloseError.java new file mode 100644 index 00000000..4622c178 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/CloseError.java @@ -0,0 +1,70 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when calling the {@code close} method on the DesktopAgent. + */ +public enum CloseError { + + /** Returned if the Desktop Agent cannot close the app's window or frame. */ + ErrorOnClose("ErrorOnClose"), + + /** + * Returned if a timeout occurs before a call to close is resolved, for any reason other than + * the app being closed. + */ + ApiTimeout("ApiTimeout"); + + private final String value; + + CloseError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static CloseError fromValue(String value) { + for (CloseError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown CloseError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/errors/FDC3ConnectionException.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/FDC3ConnectionException.java similarity index 92% rename from fdc3api/src/main/java/com/finos/fdc3/api/errors/FDC3ConnectionException.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/errors/FDC3ConnectionException.java index 6fe806b6..ceffc562 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/errors/FDC3ConnectionException.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/FDC3ConnectionException.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.finos.fdc3.api.errors; +package org.finos.fdc3.api.errors; /** * Exception used for errors connecting to FDC3 desktop agent diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/OpenError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/OpenError.java new file mode 100644 index 00000000..67493aae --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/OpenError.java @@ -0,0 +1,100 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when calling the {@code open} method on the DesktopAgent. + */ +public enum OpenError { + + /** Returned if the specified application is not found. */ + AppNotFound("AppNotFound"), + + /** Returned if the specified application fails to launch correctly. */ + ErrorOnLaunch("ErrorOnLaunch"), + + /** + * Returned if the specified application launches but fails to add a context listener in + * order to receive the context passed to the {@code fdc3.open} call. + */ + AppTimeout("AppTimeout"), + + /** + * Returned if the FDC3 desktop agent implementation is not currently able to handle the + * request. + */ + ResolverUnavailable("ResolverUnavailable"), + + /** + * Returned if a call to the {@code open} function is made with an invalid context argument. + * Contexts should be objects with at least a {@code type} field that has a string value. + */ + MalformedContext("MalformedContext"), + + /** + * Returned if the specified Desktop Agent is not found, via a connected Desktop Agent + * Bridge. Experimental. + */ + DesktopAgentNotFound("DesktopAgentNotFound"), + + /** + * Returned if a timeout occurs before a call to open is resolved for any reason other than + * the app not adding its context listener in time. + */ + ApiTimeout("ApiTimeout"), + + /** Returned when incorrect arguments are passed to API calls. */ + InvalidArguments("InvalidArguments"); + + private final String value; + + OpenError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static OpenError fromValue(String value) { + for (OpenError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown OpenError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResolveError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResolveError.java new file mode 100644 index 00000000..7cd374d7 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResolveError.java @@ -0,0 +1,136 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when calling {@code findIntent}, {@code findIntentsByContext}, + * {@code raiseIntent} or {@code raiseIntentForContext}. + */ +public enum ResolveError { + + /** + * Should be returned if no apps are available that can resolve the intent and context + * combination. + */ + NoAppsFound("NoAppsFound"), + + /** + * Returned if the FDC3 desktop agent implementation is not currently able to handle the + * request. + */ + ResolverUnavailable("ResolverUnavailable"), + + /** + * Returned if the user cancelled the resolution request, for example by closing or + * cancelling a resolver UI. Note that the wire value differs from the constant name. + */ + UserCancelled("UserCancelledResolution"), + + /** + * Should be returned if a timeout cancels an intent resolution that required user + * interaction. Use {@link #ResolverUnavailable} where a resolver UI itself fails. + */ + ResolverTimeout("ResolverTimeout"), + + /** + * Returned if a specified target application is not available or a new instance of it + * cannot be opened. + */ + TargetAppUnavailable("TargetAppUnavailable"), + + /** + * Returned if a specified target application instance is not available, for example because + * it has been closed. + */ + TargetInstanceUnavailable("TargetInstanceUnavailable"), + + /** + * Returned if the intent and context could not be delivered to the selected application or + * instance, for example because it did not add an intent handler within a timeout. + */ + IntentDeliveryFailed("IntentDeliveryFailed"), + + /** + * Returned if a call to one of the {@code raiseIntent} functions is made with an invalid + * context argument. Contexts should be objects with at least a {@code type} field that has + * a string value. + */ + MalformedContext("MalformedContext"), + + /** + * Returned if {@code fdc3.addIntentListener} is called for an intent the application has + * already added a listener for and has not subsequently removed. + */ + IntentListenerConflict("IntentListenerConflict"), + + /** + * Returned if the specified Desktop Agent is not found, via a connected Desktop Agent + * Bridge. Experimental. + */ + DesktopAgentNotFound("DesktopAgentNotFound"), + + /** + * Returned if a timeout occurs before the API call is resolved, for any reason other than + * the resolver timing out (use {@link #ResolverTimeout}) or an app launched by a + * {@code raiseIntent} function not adding its intent listener in time (use + * {@link #IntentDeliveryFailed}). + */ + ApiTimeout("ApiTimeout"), + + /** Returned when incorrect arguments are passed to API calls. */ + InvalidArguments("InvalidArguments"); + + private final String value; + + ResolveError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. This is the only correct + * way to interpret a received error string, since {@link #UserCancelled} is transmitted as + * {@code UserCancelledResolution}. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static ResolveError fromValue(String value) { + for (ResolveError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown ResolveError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResultError.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResultError.java new file mode 100644 index 00000000..292d7ccc --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/errors/ResultError.java @@ -0,0 +1,76 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Errors that can be encountered when retrieving an intent result. + */ +public enum ResultError { + + /** + * Returned if the intent handler exited without returning a valid result: a Context, a + * Channel, or nothing at all. + */ + NoResultReturned("NoResultReturned"), + + /** + * Returned if the intent handler function processing the raised intent throws an error or + * rejects the promise it returned. + */ + IntentHandlerRejected("IntentHandlerRejected"), + + /** Returned if a timeout occurs before the {@code getResult()} call is resolved. */ + ApiTimeout("ApiTimeout"); + + private final String value; + + ResultError(String value) { + this.value = value; + } + + /** The value carried in DACP messages, which is not always the constant name. */ + @JsonValue + public String getValue() { + return value; + } + + /** + * Maps a value received from a Desktop Agent back to a constant. + * + * @param value the value as it appears on the wire + * @return the matching constant + * @throws IllegalArgumentException if no constant carries that value + */ + @JsonCreator + public static ResultError fromValue(String value) { + for (ResultError candidate : values()) { + if (candidate.value.equals(value)) { + return candidate; + } + } + throw new IllegalArgumentException("Unknown ResultError value: " + value); + } + + @Override + public String toString() { + return value; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AntiReplayClaims.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AntiReplayClaims.java new file mode 100644 index 00000000..c1ed2fd4 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AntiReplayClaims.java @@ -0,0 +1,88 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AntiReplayClaims { + + private long iat; + private long exp; + private String jti; + + public AntiReplayClaims() { + } + + public AntiReplayClaims(long iat, long exp, String jti) { + this.iat = iat; + this.exp = exp; + this.jti = jti; + } + + @JsonProperty("iat") + public long getIat() { + return iat; + } + + public void setIat(long iat) { + this.iat = iat; + } + + @JsonProperty("exp") + public long getExp() { + return exp; + } + + public void setExp(long exp) { + this.exp = exp; + } + + @JsonProperty("jti") + public String getJti() { + return jti; + } + + public void setJti(String jti) { + this.jti = jti; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + AntiReplayClaims that = (AntiReplayClaims) other; + return iat == that.iat && exp == that.exp && Objects.equals(jti, that.jti); + } + + @Override + public int hashCode() { + return Objects.hash(iat, exp, jti); + } + + @Override + public String toString() { + return "AntiReplayClaims{iat=" + iat + ", exp=" + exp + ", jti=" + jti + "}"; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppIntent.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppIntent.java new file mode 100644 index 00000000..69b1ef2a --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppIntent.java @@ -0,0 +1,63 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * An interface that relates an intent to apps. + * + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AppIntent { + + private AppMetadata[] apps; + private IntentMetadata intent; + + /** + * Default constructor for Jackson deserialization. + */ + public AppIntent() { + } + + /** + * Details of applications that can resolve the intent. + */ + @JsonProperty("apps") + public AppMetadata[] getApps() { + return apps; + } + + public void setApps(AppMetadata[] apps) { + this.apps = apps; + } + + /** + * Details of the intent whose relationship to resolving applications is being described. + */ + @JsonProperty("intent") + public IntentMetadata getIntent() { + return intent; + } + + public void setIntent(IntentMetadata intent) { + this.intent = intent; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppMetadata.java new file mode 100644 index 00000000..f58c947a --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppMetadata.java @@ -0,0 +1,176 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Collection; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.finos.fdc3.api.types.AppIdentifier; + +/** + * Extends an `AppIdentifier`, describing an application or instance of an application, with additional + * descriptive metadata that is usually provided by an FDC3 App Directory that the desktop agent connects to. + * + * The additional information from an app directory can aid in rendering UI elements, such as a launcher + * menu or resolver UI. This includes a title, description, tooltip and icon and screenshot URLs. + * + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the `app` argument + * of `fdc3.open`, `fdc3.raiseIntent` etc. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AppMetadata extends AppIdentifier { + + private String name; + private String version; + private Map instanceMetadata; + private String title; + private String tooltip; + private String description; + private Collection icons; + private Collection screenshots; + private String resultType; + + /** + * Default constructor for Jackson deserialization. + */ + public AppMetadata() { + } + + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now require an + * `AppIdentifier` with `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to this field. + */ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** The Version of the application. */ + @JsonProperty("version") + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + /** + * An optional set of, implementation specific, metadata fields that can be used to disambiguate instances, + * such as a window title or screen position. Must only be set if `instanceId` is set. + */ + @JsonProperty("instanceMetadata") + public Map getInstanceMetadata() { + return instanceMetadata; + } + + public void setInstanceMetadata(Map instanceMetadata) { + this.instanceMetadata = instanceMetadata; + } + + /** A more user-friendly application title that can be used to render UI elements. */ + @JsonProperty("title") + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + /** A tooltip for the application that can be used to render UI elements. */ + @JsonProperty("tooltip") + public String getTooltip() { + return tooltip; + } + + public void setTooltip(String tooltip) { + this.tooltip = tooltip; + } + + /** A longer, multi-paragraph description for the application that could include markup. */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + /** A list of icon URLs for the application that can be used to render UI elements. */ + @JsonProperty("icons") + public Collection getIcons() { + return icons; + } + + public void setIcons(Collection icons) { + this.icons = icons; + } + + /** Images representing the app in common usage scenarios that can be used to render UI elements. */ + @JsonProperty("screenshots") + public Collection getScreenshots() { + return screenshots; + } + + public void setScreenshots(Collection screenshots) { + this.screenshots = screenshots; + } + + /** + * The type of output returned for any intent specified during resolution. May express a particular + * context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel that will receive + * a specified type (e.g. "channel<fdc3.instrument>"). + */ + @JsonProperty("resultType") + public String getResultType() { + return resultType; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + + /** + * Includes the descriptive fields for readability. Equality is deliberately not overridden: + * see {@link AppIdentifier#equals}, which compares identity only so that metadata returned + * by {@code findInstances} matches the identifier it describes. + */ + @Override + public String toString() { + StringBuilder text = new StringBuilder("AppMetadata{appId=").append(getAppId()); + if (getInstanceId() != null) { + text.append(", instanceId=").append(getInstanceId()); + } + if (title != null) { + text.append(", title=").append(title); + } else if (name != null) { + text.append(", name=").append(name); + } + return text.append('}').toString(); + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Currency.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppProvidableContextMetadata.java similarity index 57% rename from fdc3api/src/main/java/com/finos/fdc3/api/context/Currency.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppProvidableContextMetadata.java index 16ce322b..156ee5fc 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Currency.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/AppProvidableContextMetadata.java @@ -1,5 +1,5 @@ -/** - * Copyright 2023 Wellington Management Company LLP +/* + * Copyright FINOS and Contributors to the FDC3 project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,23 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.finos.fdc3.api.metadata; + +import java.util.Map; -package com.finos.fdc3.api.context; +/** + * Metadata that may be provided by an app when calling broadcast, open, or raiseIntent, + * to be passed on to receiving apps. + */ +public interface AppProvidableContextMetadata extends SecurityMetadata { -import com.fasterxml.jackson.annotation.JsonPropertyOrder; + String getTraceId(); -import java.util.Map; + void setTraceId(String traceId); -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Currency extends Context { - public static String TYPE = "fdc3.currency"; - public static Map VALID_ID_KEYS = Map.of("CURRENCY_ISOCODE", true); + Map getCustom(); - public Currency() { - super(TYPE); - } + void setCustom(Map custom); } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ContextMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ContextMetadata.java new file mode 100644 index 00000000..f9687287 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ContextMetadata.java @@ -0,0 +1,238 @@ +/* + * Copyright FINOS and Contributors to the FDC3 project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.finos.fdc3.api.metadata; + +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.finos.fdc3.api.types.AppIdentifier; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * Metadata for context and intent messages, stored as a map (same pattern as {@link org.finos.fdc3.api.context.Context}). + *

+ * Implements {@link AppProvidableContextMetadata} for outbound app-provided fields and + * {@link DesktopAgentProvidableContextMetadata} for optional Desktop Agent fields. + * When received via listeners, {@link #getSource()} and {@link #getTimestamp()} are + * typically populated by the Desktop Agent. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ContextMetadata extends HashMap + implements AppProvidableContextMetadata, DesktopAgentProvidableContextMetadata { + + public ContextMetadata() { + super(); + } + + public ContextMetadata(Map initial) { + super(); + if (initial != null) { + mergeFrom(initial); + } + } + + /** Returns a new empty instance suitable for outbound app-provided metadata. */ + public static ContextMetadata appProvidable() { + return new ContextMetadata(); + } + + /** Returns an unmodifiable copy of this metadata. */ + public Map asMap() { + return Collections.unmodifiableMap(new LinkedHashMap<>(this)); + } + + /** Returns a mutable copy for wire serialization. */ + public Map toMap() { + return new LinkedHashMap<>(this); + } + + @Override + public String getTraceId() { + return (String) get("traceId"); + } + + @Override + public void setTraceId(String traceId) { + putOrRemove("traceId", traceId); + } + + @Override + public DetachedSignature getSignature() { + return getTyped("signature", DetachedSignature.class); + } + + @Override + public void setSignature(DetachedSignature signature) { + putOrRemove("signature", signature); + } + + @Override + public AntiReplayClaims getAntiReplay() { + return getTyped("antiReplay", AntiReplayClaims.class); + } + + @Override + public void setAntiReplay(AntiReplayClaims antiReplay) { + putOrRemove("antiReplay", antiReplay); + } + + @Override + @SuppressWarnings("unchecked") + public Map getCustom() { + Object custom = get("custom"); + if (custom instanceof Map) { + return (Map) custom; + } + return null; + } + + @Override + public void setCustom(Map custom) { + putOrRemove("custom", custom); + } + + @Override + public Instant getTimestamp() { + Object value = get("timestamp"); + if (value instanceof Instant) { + return (Instant) value; + } + if (value instanceof String) { + return Instant.parse((String) value); + } + return null; + } + + @Override + public void setTimestamp(Instant timestamp) { + putOrRemove("timestamp", timestamp); + } + + @Override + public AppIdentifier getSource() { + Object source = get("source"); + if (source instanceof AppIdentifier) { + return (AppIdentifier) source; + } + if (source instanceof Map) { + return AppIdentifier.fromMap(castMap(source)); + } + return null; + } + + @Override + public void setSource(AppIdentifier source) { + putOrRemove("source", source); + } + + public static ContextMetadata fromMap(Map map) { + if (map == null) { + return null; + } + if (map instanceof ContextMetadata) { + return (ContextMetadata) map; + } + ContextMetadata metadata = new ContextMetadata(); + metadata.mergeFrom(map); + return metadata; + } + + public void mergeFrom(Map map) { + if (map == null) { + return; + } + Object source = map.get("source"); + if (source != null) { + setSource(source instanceof AppIdentifier ? (AppIdentifier) source : AppIdentifier.fromMap(castMap(source))); + } + Object timestamp = map.get("timestamp"); + if (timestamp instanceof Instant) { + setTimestamp((Instant) timestamp); + } else if (timestamp instanceof String) { + setTimestamp(Instant.parse((String) timestamp)); + } + setTraceId((String) map.get("traceId")); + Object signature = map.get("signature"); + if (signature instanceof DetachedSignature) { + setSignature((DetachedSignature) signature); + } else if (signature instanceof Map) { + setSignature(mapToDetachedSignature(castMap(signature))); + } + Object antiReplay = map.get("antiReplay"); + if (antiReplay instanceof AntiReplayClaims) { + setAntiReplay((AntiReplayClaims) antiReplay); + } else if (antiReplay instanceof Map) { + setAntiReplay(mapToAntiReplay(castMap(antiReplay))); + } + Object custom = map.get("custom"); + if (custom instanceof Map) { + setCustom(castMap(custom)); + } + for (Map.Entry entry : map.entrySet()) { + if (!containsKey(entry.getKey())) { + put(entry.getKey(), entry.getValue()); + } + } + } + + private void putOrRemove(String key, Object value) { + if (value == null) { + remove(key); + } else { + put(key, value); + } + } + + private T getTyped(String key, Class type) { + Object value = get(key); + if (type.isInstance(value)) { + return type.cast(value); + } + if (value instanceof Map) { + if (type == DetachedSignature.class) { + return type.cast(mapToDetachedSignature(castMap(value))); + } + if (type == AntiReplayClaims.class) { + return type.cast(mapToAntiReplay(castMap(value))); + } + } + return null; + } + + @SuppressWarnings("unchecked") + private static Map castMap(Object value) { + return (Map) value; + } + + private static DetachedSignature mapToDetachedSignature(Map map) { + DetachedSignature sig = new DetachedSignature(); + sig.setProtectedHeader((String) map.get("protected")); + sig.setSignature((String) map.get("signature")); + return sig; + } + + private static AntiReplayClaims mapToAntiReplay(Map map) { + Object iat = map.get("iat"); + Object exp = map.get("exp"); + long iatVal = iat instanceof Number ? ((Number) iat).longValue() : Long.parseLong(String.valueOf(iat)); + long expVal = exp instanceof Number ? ((Number) exp).longValue() : Long.parseLong(String.valueOf(exp)); + return new AntiReplayClaims(iatVal, expVal, (String) map.get("jti")); + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/Image.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DesktopAgentProvidableContextMetadata.java similarity index 53% rename from fdc3api/src/main/java/com/finos/fdc3/api/metadata/Image.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DesktopAgentProvidableContextMetadata.java index 82434efb..47b8bca6 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/Image.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DesktopAgentProvidableContextMetadata.java @@ -1,5 +1,5 @@ -/** - * Copyright 2023 Wellington Management Company LLP +/* + * Copyright FINOS and Contributors to the FDC3 project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.finos.fdc3.api.metadata; + +import java.time.Instant; -package com.finos.fdc3.api.metadata; +import org.finos.fdc3.api.types.AppIdentifier; -import java.util.Optional; +/** + * Metadata fields that may be provided by the Desktop Agent (optional source and timestamp). + */ +public interface DesktopAgentProvidableContextMetadata extends SecurityMetadata { -public interface Image { - /** The image url. */ - public String getSrc(); + Instant getTimestamp(); - /** The image dimension, formatted as `x`. */ - public Optional getSize(); + void setTimestamp(Instant timestamp); - /** Image media type. If not present the Desktop Agent may use the src file extension. */ - public Optional getType(); + AppIdentifier getSource(); - /** Caption for the image. */ - public Optional getLabel(); + void setSource(AppIdentifier source); } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DetachedSignature.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DetachedSignature.java new file mode 100644 index 00000000..0cde3746 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DetachedSignature.java @@ -0,0 +1,80 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DetachedSignature { + + private String protectedHeader; + private String signature; + + public DetachedSignature() { + } + + public DetachedSignature(String protectedHeader, String signature) { + this.protectedHeader = protectedHeader; + this.signature = signature; + } + + @JsonProperty("protected") + public String getProtectedHeader() { + return protectedHeader; + } + + public void setProtectedHeader(String protectedHeader) { + this.protectedHeader = protectedHeader; + } + + @JsonProperty("signature") + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + DetachedSignature that = (DetachedSignature) other; + return Objects.equals(protectedHeader, that.protectedHeader) + && Objects.equals(signature, that.signature); + } + + @Override + public int hashCode() { + return Objects.hash(protectedHeader, signature); + } + + /** Omits the signature value itself, which is long and not useful in a log line. */ + @Override + public String toString() { + return "DetachedSignature{protected=" + protectedHeader + + ", signature=" + (signature == null ? "null" : "present") + "}"; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DisplayMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DisplayMetadata.java new file mode 100644 index 00000000..b25a8422 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/DisplayMetadata.java @@ -0,0 +1,126 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; +import java.util.Objects; + +/** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + * + * A system channel will be global enough to have a presence across many apps. This gives us + * some hints to render them in a standard way. It is assumed it may have other properties too, + * but if it has these, this is their meaning. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DisplayMetadata { + + private String name; + private String color; + private String glyph; + + /** + * Default constructor for Jackson deserialization. + */ + public DisplayMetadata() { + } + + public DisplayMetadata(String name, String color, String glyph) { + this.name = name; + this.color = color; + this.glyph = glyph; + } + + /** + * A user-readable name for this channel, e.g: `"Red"`. + */ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. + */ + @JsonProperty("color") + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + /** + * A URL of an image that can be used to display this channel. + */ + @JsonProperty("glyph") + public String getGlyph() { + return glyph; + } + + public void setGlyph(String glyph) { + this.glyph = glyph; + } + + /** + * Create a DisplayMetadata from a Map. + */ + public static DisplayMetadata fromMap(Map map) { + if (map == null) { + return null; + } + String name = (String) map.get("name"); + String color = (String) map.get("color"); + String glyph = (String) map.get("glyph"); + return new DisplayMetadata(name, color, glyph); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + DisplayMetadata that = (DisplayMetadata) other; + return Objects.equals(name, that.name) + && Objects.equals(color, that.color) + && Objects.equals(glyph, that.glyph); + } + + @Override + public int hashCode() { + return Objects.hash(name, color, glyph); + } + + @Override + public String toString() { + return "DisplayMetadata{name=" + name + ", color=" + color + ", glyph=" + glyph + "}"; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Icon.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Icon.java new file mode 100644 index 00000000..28f380ab --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Icon.java @@ -0,0 +1,105 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Describes an Icon image that may be used to represent the application. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Icon { + + private String src; + private String size; + private String type; + + /** + * Default constructor for Jackson deserialization. + */ + public Icon() { + } + + public Icon(String src, String size, String type) { + this.src = src; + this.size = size; + this.type = type; + } + + /** + * The icon url. + */ + @JsonProperty("src") + public String getSrc() { + return src; + } + + public void setSrc(String src) { + this.src = src; + } + + /** + * The icon dimension, formatted as {@code x}. + */ + @JsonProperty("size") + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + + /** + * Icon media type. If not present the Desktop Agent may use the src file extension. + */ + @JsonProperty("type") + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + Icon that = (Icon) other; + return Objects.equals(src, that.src) + && Objects.equals(size, that.size) + && Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hash(src, size, type); + } + + @Override + public String toString() { + return "Icon{src=" + src + ", size=" + size + ", type=" + type + "}"; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Image.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Image.java new file mode 100644 index 00000000..d2561288 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/Image.java @@ -0,0 +1,121 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Image { + + private String src; + private String size; + private String type; + private String label; + + /** + * Default constructor for Jackson deserialization. + */ + public Image() { + } + + public Image(String src, String size, String type, String label) { + this.src = src; + this.size = size; + this.type = type; + this.label = label; + } + + /** + * The image url. + */ + @JsonProperty("src") + public String getSrc() { + return src; + } + + public void setSrc(String src) { + this.src = src; + } + + /** + * The image dimension, formatted as {@code x}. + */ + @JsonProperty("size") + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + @JsonProperty("type") + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * Caption for the image. + */ + @JsonProperty("label") + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + Image that = (Image) other; + return Objects.equals(src, that.src) + && Objects.equals(size, that.size) + && Objects.equals(type, that.type) + && Objects.equals(label, that.label); + } + + @Override + public int hashCode() { + return Objects.hash(src, size, type, label); + } + + @Override + public String toString() { + return "Image{src=" + src + ", size=" + size + ", type=" + type + ", label=" + label + "}"; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ImplementationMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ImplementationMetadata.java new file mode 100644 index 00000000..6600c095 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/ImplementationMetadata.java @@ -0,0 +1,145 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ImplementationMetadata { + + private String fdc3Version; + private String provider; + private String providerVersion; + private AppMetadata appMetadata; + private OptionalFeatures optionalFeatures; + + /** + * Default constructor for Jackson deserialization. + */ + public ImplementationMetadata() { + } + + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + @JsonProperty("fdc3Version") + public String getFdc3Version() { + return fdc3Version; + } + + public void setFdc3Version(String fdc3Version) { + this.fdc3Version = fdc3Version; + } + + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, OpenFin etc.). + */ + @JsonProperty("provider") + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + @JsonProperty("providerVersion") + public String getProviderVersion() { + return providerVersion; + } + + public void setProviderVersion(String providerVersion) { + this.providerVersion = providerVersion; + } + + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST include at least the `appId` and `instanceId`). + */ + @JsonProperty("appMetadata") + public AppMetadata getAppMetadata() { + return appMetadata; + } + + public void setAppMetadata(AppMetadata appMetadata) { + this.appMetadata = appMetadata; + } + + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + @JsonProperty("optionalFeatures") + public OptionalFeatures getOptionalFeatures() { + return optionalFeatures; + } + + public void setOptionalFeatures(OptionalFeatures optionalFeatures) { + this.optionalFeatures = optionalFeatures; + } + + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class OptionalFeatures { + + private boolean userChannelMembershipAPIs; + private boolean desktopAgentBridging; + + /** + * Default constructor for Jackson deserialization. + */ + public OptionalFeatures() { + } + + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + @JsonProperty("UserChannelMembershipAPIs") + public boolean isUserChannelMembershipAPIs() { + return userChannelMembershipAPIs; + } + + public void setUserChannelMembershipAPIs(boolean userChannelMembershipAPIs) { + this.userChannelMembershipAPIs = userChannelMembershipAPIs; + } + + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + @JsonProperty("DesktopAgentBridging") + public boolean isDesktopAgentBridging() { + return desktopAgentBridging; + } + + public void setDesktopAgentBridging(boolean desktopAgentBridging) { + this.desktopAgentBridging = desktopAgentBridging; + } + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentMetadata.java new file mode 100644 index 00000000..c3982d0e --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentMetadata.java @@ -0,0 +1,89 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.metadata; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Metadata describing an Intent. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class IntentMetadata { + + private String name; + private String displayName; + + /** + * Default constructor for Jackson deserialization. + */ + public IntentMetadata() { + } + + public IntentMetadata(String name, String displayName) { + this.name = name; + this.displayName = displayName; + } + + /** + * The unique name of the intent that can be invoked by the raiseIntent call. + */ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * Display name for the intent. + */ + @JsonProperty("displayName") + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + IntentMetadata that = (IntentMetadata) other; + return Objects.equals(name, that.name) && Objects.equals(displayName, that.displayName); + } + + @Override + public int hashCode() { + return Objects.hash(name, displayName); + } + + @Override + public String toString() { + return "IntentMetadata{name=" + name + ", displayName=" + displayName + "}"; + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentResolution.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentResolution.java similarity index 53% rename from fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentResolution.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentResolution.java index 3d80ae44..21c0e31b 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/IntentResolution.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/IntentResolution.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,39 +14,48 @@ * limitations under the License. */ -package com.finos.fdc3.api.metadata; +package org.finos.fdc3.api.metadata; import java.util.Optional; import java.util.concurrent.CompletionStage; -import com.finos.fdc3.api.types.AppIdentifier; -import com.finos.fdc3.api.types.IntentResult; +import org.finos.fdc3.api.types.AppIdentifier; +import org.finos.fdc3.api.types.IntentResult; /** * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resoluion.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` + *

+ * Resolving a "Chain" type intent, where the result is not of interest: + *

{@code
+ * agent.raiseIntent("intentName", context);
+ * }
+ *

+ * Resolving a "Client-Service" type intent, where the handler returns either data or a + * {@link org.finos.fdc3.api.channel.Channel}: + *

{@code
+ * agent.raiseIntent("intentName", context)
+ *     .thenCompose(resolution -> resolution.getResult()
+ *         .thenAccept(result -> {
+ *             if (result instanceof Channel) {
+ *                 Channel channel = (Channel) result;
+ *                 System.out.println(resolution.getSource() + " returned channel " + channel.getId());
+ *             } else if (result != null) {
+ *                 System.out.println(resolution.getSource() + " returned data: " + result);
+ *             } else {
+ *                 System.out.println(resolution.getSource() + " did not return data");
+ *             }
+ *         })
+ *         .exceptionally(error -> {
+ *             System.out.println(resolution.getSource() + " returned an error: " + error.getMessage());
+ *             return null;
+ *         }));
+ * }
+ *

+ * The resolving instance can then be targeted by a further intent, using the identifier this + * resolution reports as its source: + *

{@code
+ * agent.raiseIntent("intentName", context, resolution.getSource());
+ * }
*/ public interface IntentResolution { /** @@ -62,11 +71,6 @@ public interface IntentResolution { */ String getIntent(); - /** - * The version number of the Intents schema being used. - */ - Optional getVersion(); - /** * Retrieves a promise that will resolve to either `Context` data returned * by the application that resolves the raised intent or a `Channel` @@ -82,4 +86,9 @@ public interface IntentResolution { * object of an invalid type. */ CompletionStage getResult(); + + /** + * Retrieves metadata about the intent result from the resolving application. + */ + CompletionStage getResultMetadata(); } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/SecurityMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/SecurityMetadata.java new file mode 100644 index 00000000..d09876e6 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/metadata/SecurityMetadata.java @@ -0,0 +1,34 @@ +/* + * Copyright FINOS and Contributors to the FDC3 project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.finos.fdc3.api.metadata; + +/** + * Signing fields that a sending app may attach to context and intent metadata. + *

+ * These are the only security fields the DACP schemas carry. The outcome of verifying a + * signature is not metadata and is never transmitted: it is produced locally by the + * receiving app's security layer, and belongs in a security library rather than here. + */ +public interface SecurityMetadata { + + DetachedSignature getSignature(); + + void setSignature(DetachedSignature signature); + + AntiReplayClaims getAntiReplay(); + + void setAntiReplay(AntiReplayClaims antiReplay); +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/types/AppIdentifier.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/AppIdentifier.java new file mode 100644 index 00000000..c628e649 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/AppIdentifier.java @@ -0,0 +1,165 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; +import java.util.Objects; + +/** + * Identifies an application, or instance of an application, and is used to target FDC3 API calls, + * such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppIdentifier` object represents a specific instance + * of the application that may be addressed using that Id. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AppIdentifier { + + private String appID; + private String instanceID; + private String desktopAgent; + + /** + * Default constructor for Jackson deserialization. + */ + public AppIdentifier() { + } + + @JsonCreator + public AppIdentifier( + @JsonProperty("appId") String appID, + @JsonProperty("instanceId") String instanceID, + @JsonProperty("desktopAgent") String desktopAgent) { + this.appID = appID; + this.instanceID = instanceID; + this.desktopAgent = desktopAgent; + } + + public AppIdentifier(String appID, String instanceID) { + this(appID, instanceID, null); + } + + public AppIdentifier(String appID) { + this(appID, null, null); + } + + /** + * The unique application identifier located within a specific application directory instance. + * An example of an appId might be 'app@sub.root'. + */ + @JsonProperty("appId") + public String getAppId() { + return appID; + } + + public void setAppId(String appID) { + this.appID = appID; + } + + /** + * An optional instance identifier, indicating that this object represents a specific instance + * of the application described. + */ + @JsonProperty("instanceId") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getInstanceId() { + return instanceID; + } + + public void setInstanceId(String instanceID) { + this.instanceID = instanceID; + } + + /** + * Identifier of the desktop agent, used in bridging. + */ + @JsonProperty("desktopAgent") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getDesktopAgent() { + return desktopAgent; + } + + public void setDesktopAgent(String desktopAgent) { + this.desktopAgent = desktopAgent; + } + + /** + * Creates an AppIdentifier from a Map representation. + * + * @param map the map containing appId, instanceId, and/or desktopAgent keys + * @return a new AppIdentifier instance, or null if the map is null + */ + public static AppIdentifier fromMap(Map map) { + if (map == null) { + return null; + } + + String appID = (String) map.get("appId"); + String instanceID = (String) map.get("instanceId"); + String desktopAgent = (String) map.get("desktopAgent"); + + return new AppIdentifier(appID, instanceID, desktopAgent); + } + + /** + * Compares the identity fields only: {@code appId}, {@code instanceId} and + * {@code desktopAgent}. + *

+ * Deliberately accepts any {@code AppIdentifier}, including an {@link + * org.finos.fdc3.api.metadata.AppMetadata}, rather than requiring an exact class match. + * {@code findInstances} returns app metadata upcast to {@code AppIdentifier}, so requiring + * an exact match would mean a plain identifier could never be found in its result. The + * descriptive fields {@code AppMetadata} adds come from an app directory and describe an + * app rather than identifying it, which is why subclasses do not refine this comparison. + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof AppIdentifier)) { + return false; + } + AppIdentifier that = (AppIdentifier) other; + return Objects.equals(appID, that.appID) + && Objects.equals(instanceID, that.instanceID) + && Objects.equals(desktopAgent, that.desktopAgent); + } + + @Override + public int hashCode() { + return Objects.hash(appID, instanceID, desktopAgent); + } + + @Override + public String toString() { + StringBuilder text = new StringBuilder("AppIdentifier{appId=").append(appID); + if (instanceID != null) { + text.append(", instanceId=").append(instanceID); + } + if (desktopAgent != null) { + text.append(", desktopAgent=").append(desktopAgent); + } + return text.append('}').toString(); + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/types/ContextHandler.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextHandler.java similarity index 79% rename from fdc3api/src/main/java/com/finos/fdc3/api/types/ContextHandler.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextHandler.java index 1cba6622..432267d7 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/types/ContextHandler.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextHandler.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.finos.fdc3.api.types; +package org.finos.fdc3.api.types; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.ContextMetadata; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; @FunctionalInterface public interface ContextHandler { diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextWithMetadata.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextWithMetadata.java new file mode 100644 index 00000000..2be08dd8 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/ContextWithMetadata.java @@ -0,0 +1,81 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.types; + +import java.util.Objects; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; + +/** + * Context object paired with its associated metadata. + */ +public class ContextWithMetadata { + + private Context context; + private ContextMetadata metadata; + + public ContextWithMetadata() { + } + + public ContextWithMetadata(Context context, ContextMetadata metadata) { + this.context = context; + this.metadata = metadata; + } + + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + + public ContextMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ContextMetadata metadata) { + this.metadata = metadata; + } + + /** + * Both {@link Context} and {@link ContextMetadata} extend {@code HashMap}, so they already + * compare by value and can be delegated to here. + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + ContextWithMetadata that = (ContextWithMetadata) other; + return Objects.equals(context, that.context) && Objects.equals(metadata, that.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(context, metadata); + } + + @Override + public String toString() { + return "ContextWithMetadata{context=" + context + ", metadata=" + metadata + "}"; + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppIntent.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/EventHandler.java similarity index 56% rename from fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppIntent.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/types/EventHandler.java index 263e2ca0..4b39aac0 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppIntent.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/EventHandler.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,21 @@ * limitations under the License. */ -package com.finos.fdc3.api.metadata; - -import java.util.Collection; +package org.finos.fdc3.api.types; /** - * An interface that relates an intent to apps + * Describes a callback that handles non-context and non-intent events from the + * Desktop Agent. + * Used when attaching listeners via {@code addEventListener}. */ -public interface AppIntent { - /** Details of the intent whose relationship to resolving applications is being described. */ - public IntentMetadata getIntent(); +@FunctionalInterface +public interface EventHandler { + + /** + * Handles an FDC3 event. + * + * @param event the event object containing type and details + */ + void handleEvent(FDC3Event event); - /** Details of applications that can resolve the intent. */ - public Collection getApps(); } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/types/FDC3Event.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/FDC3Event.java new file mode 100644 index 00000000..4972d45f --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/FDC3Event.java @@ -0,0 +1,140 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Type representing the event object passed to event handlers subscribed to + * FDC3 events via the {@code addEventListener} method. + * + * Events will always include both {@code type} and {@code details} properties, + * which describe the type of event and any additional details, respectively. + */ +public class FDC3Event { + + /** + * Enumeration of FDC3 event types. + */ + public enum Type { + ADD_CONTEXT_LISTENER("addContextListener"), + /** Listener / event type string for PrivateChannel unsubscribe events. */ + ON_UNSUBSCRIBE("unsubscribe"), + /** Listener / event type string for PrivateChannel disconnect events. */ + ON_DISCONNECT("disconnect"), + USER_CHANNEL_CHANGED("userChannelChanged"), + CONTEXT_CLEARED("contextCleared"); + + + private final String value; + + Type(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @JsonCreator + public static Type fromValue(String value) { + for (Type type : Type.values()) { + if (type.value.equals(value)) { + return type; + } + } + throw new IllegalArgumentException("Unknown FDC3 event type: " + value); + } + + /** + * DACP wire enum value for {@code addEventListenerRequest.payload.type} + * (e.g. {@code USER_CHANNEL_CHANGED}). + */ + public String toWireValue() { + return name(); + } + + /** + * DACP inbound agent event message {@code type} + * (e.g. {@code channelChangedEvent}). + */ + public String toMessageType() { + switch (this) { + case USER_CHANNEL_CHANGED: + return "channelChangedEvent"; + case CONTEXT_CLEARED: + return "contextClearedEvent"; + case ADD_CONTEXT_LISTENER: + return "privateChannelOnAddContextListenerEvent"; + case ON_UNSUBSCRIBE: + return "privateChannelOnUnsubscribeEvent"; + case ON_DISCONNECT: + return "privateChannelOnDisconnectEvent"; + default: + throw new IllegalStateException("No DACP message type for: " + this); + } + } + + /** + * Maps a DACP agent event message type to the corresponding API event type, + * or {@code null} if the message is not a recognised FDC3 event. + */ + public static Type fromMessageType(String messageType) { + if (messageType == null) { + return null; + } + for (Type type : Type.values()) { + if (type.toMessageType().equals(messageType)) { + return type; + } + } + return null; + } + + @Override + public String toString() { + return value; + } + } + + private final Type type; + private final Object details; + + @JsonCreator + public FDC3Event(@JsonProperty("type") Type type, @JsonProperty("details") Object details) { + this.type = type; + this.details = details; + } + + /** + * Returns the typed enum constant for this event, or {@code null} for + * wildcard listeners receiving unmapped agent events. + */ + public Type getType() { + return type; + } + + /** + * Returns the details object containing additional information about the event. + */ + public Object getDetails() { + return details; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentHandler.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentHandler.java new file mode 100644 index 00000000..757ac202 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentHandler.java @@ -0,0 +1,62 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.types; + +import java.util.Optional; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.ContextMetadata; + +/** + * Callback invoked when an intent is raised to this application. + *

+ * Registered via {@link org.finos.fdc3.api.DesktopAgent#addIntentListener(String, IntentHandler)} + * (and related overloads). The handler receives the raised context and metadata about the + * message, and may return a result to the raising application through + * {@link org.finos.fdc3.api.metadata.IntentResolution}. + */ +@FunctionalInterface +public interface IntentHandler { + + /** + * Handles a raised intent. + * + * @param context the context object supplied with the raised intent + * @param contextMetadata metadata for the raised intent (originating app, timestamp, and any + * app-providable fields forwarded by the Desktop Agent); never + * {@code null}, though individual fields may be absent + * @return a {@link CompletionStage} that completes with an optional result for the raising + * app. Use {@link Optional#empty()} (or complete with {@code null} inside the + * optional) when there is no result. A present value SHOULD be one of: + *

    + *
  • {@link Context} — context data returned to the raiser via + * {@link org.finos.fdc3.api.metadata.IntentResolution#getResult()}
  • + *
  • {@link ContextWithMetadata} — context plus app-providable metadata; the + * Desktop Agent merges that metadata and exposes it via + * {@link org.finos.fdc3.api.metadata.IntentResolution#getResultMetadata()}, + * while {@code getResult()} returns only the {@link Context}
  • + *
  • {@link org.finos.fdc3.api.channel.Channel} or + * {@link org.finos.fdc3.api.channel.PrivateChannel} — a channel over which + * further responses will be streamed
  • + *
+ * If the stage completes exceptionally, no {@code intentResultRequest} is sent + * ({@code IntentHandlerRejected} is a Desktop Agent concern, not reportable over DACP). + */ + CompletionStage> handleIntent(Context context, ContextMetadata contextMetadata); + +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/types/IntentResult.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentResult.java similarity index 75% rename from fdc3api/src/main/java/com/finos/fdc3/api/types/IntentResult.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentResult.java index 397def66..01f39034 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/types/IntentResult.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/IntentResult.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,17 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.finos.fdc3.api.types; +package org.finos.fdc3.api.types; -import com.finos.fdc3.api.channel.Channel; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.IntentResolution; +import org.finos.fdc3.api.channel.Channel; +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.IntentResolution; /** * Describes results that an {@link IntentHandler} may optionally return that should be communicated back to the app that raised the * intent, via the {@link IntentResolution}. Represented as a union type in TypeScript, however in Java it is a marker interface - * implemented by {@link Context} and {@link Channel} + * implemented by {@link Context} and {@link Channel}. */ public interface IntentResult { - } diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/types/Listener.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/Listener.java similarity index 80% rename from fdc3api/src/main/java/com/finos/fdc3/api/types/Listener.java rename to fdc3-standard/src/main/java/org/finos/fdc3/api/types/Listener.java index 1bcbe60b..a4f3ee0a 100644 --- a/fdc3api/src/main/java/com/finos/fdc3/api/types/Listener.java +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/types/Listener.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 Wellington Management Company LLP + * Copyright FINOS and its Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,13 @@ * limitations under the License. */ -package com.finos.fdc3.api.types; +package org.finos.fdc3.api.types; + +import java.util.concurrent.CompletionStage; public interface Listener { /** * Unsubscribe the listener object. */ - public void unsubscribe(); + CompletionStage unsubscribe(); } diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/ChannelSelector.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/ChannelSelector.java new file mode 100644 index 00000000..d6d57539 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/ChannelSelector.java @@ -0,0 +1,48 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.ui; + +import java.util.List; +import java.util.function.Consumer; + +import org.finos.fdc3.api.channel.Channel; + +/** + * Interface used by the desktop agent proxy to handle the channel selection process. + *

+ * Implementations of this interface provide a UI for users to select which user channel + * they want to join. The Desktop Agent proxy will call {@link #updateChannel} when + * the channel list or current channel changes, and the implementation should call + * the callback set via {@link #setChannelChangeCallback} when the user selects a channel. + */ +public interface ChannelSelector extends Connectable { + + /** + * Set the callback to be invoked when the user selects a different channel. + * + * @param callback the callback, receiving the channel ID or null if leaving all channels + */ + void setChannelChangeCallback(Consumer callback); + + /** + * Called when the list of user channels is updated, or the selected channel changes. + * + * @param channelId the current channel ID, or null if no channel is selected + * @param availableChannels the list of available user channels + */ + void updateChannel(String channelId, List availableChannels); +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/Connectable.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/Connectable.java new file mode 100644 index 00000000..40fc8101 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/Connectable.java @@ -0,0 +1,42 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.ui; + +import java.util.concurrent.CompletionStage; + +/** + * Interface for objects that support connection lifecycle. + *

+ * This is used by UI components like {@link ChannelSelector} and {@link IntentResolver} + * that may need to connect to external resources. + */ +public interface Connectable { + + /** + * Connect to the underlying resource. + * + * @return a CompletionStage that completes when connected + */ + CompletionStage connect(); + + /** + * Disconnect from the underlying resource. + * + * @return a CompletionStage that completes when disconnected + */ + CompletionStage disconnect(); +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolutionChoice.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolutionChoice.java new file mode 100644 index 00000000..fe36eb18 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolutionChoice.java @@ -0,0 +1,60 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.ui; + +import org.finos.fdc3.api.types.AppIdentifier; + +/** + * Represents the user's choice from an intent resolver. + *

+ * This is returned by {@link IntentResolver#chooseIntent} when the user + * selects an application to handle an intent. + */ +public class IntentResolutionChoice { + + private final String intent; + private final AppIdentifier appId; + + /** + * Creates a new IntentResolutionChoice. + * + * @param intent the intent that was chosen + * @param appId the application identifier chosen to handle the intent + */ + public IntentResolutionChoice(String intent, AppIdentifier appId) { + this.intent = intent; + this.appId = appId; + } + + /** + * Gets the intent that was chosen. + * + * @return the intent name + */ + public String getIntent() { + return intent; + } + + /** + * Gets the application identifier chosen to handle the intent. + * + * @return the app identifier + */ + public AppIdentifier getAppId() { + return appId; + } +} diff --git a/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolver.java b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolver.java new file mode 100644 index 00000000..40205520 --- /dev/null +++ b/fdc3-standard/src/main/java/org/finos/fdc3/api/ui/IntentResolver.java @@ -0,0 +1,44 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.ui; + +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.finos.fdc3.api.context.Context; +import org.finos.fdc3.api.metadata.AppIntent; + +/** + * Interface used by the desktop agent proxy to handle the intent resolution process. + *

+ * Implementations of this interface provide a UI for users to choose which application + * should handle an intent when multiple applications are available. + */ +public interface IntentResolver extends Connectable { + + /** + * Called when the user needs to resolve an intent. + *

+ * The implementation should display a UI allowing the user to select from the + * available applications that can handle the intent(s). + * + * @param appIntents the available intents and apps that can handle them + * @param context the context being passed to the intent + * @return a CompletionStage containing the user's choice; the stage may complete with {@code null} to indicate cancellation + */ + CompletionStage chooseIntent(List appIntents, Context context); +} diff --git a/fdc3-standard/src/test/java/org/finos/fdc3/api/errors/ErrorEnumWireFormatTest.java b/fdc3-standard/src/test/java/org/finos/fdc3/api/errors/ErrorEnumWireFormatTest.java new file mode 100644 index 00000000..426eedba --- /dev/null +++ b/fdc3-standard/src/test/java/org/finos/fdc3/api/errors/ErrorEnumWireFormatTest.java @@ -0,0 +1,100 @@ +/** + * Copyright FINOS and its Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.finos.fdc3.api.errors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; + +/** + * Checks that every FDC3 error enum survives a trip through Jackson unchanged. + *

+ * These enums cross the wire in DACP messages, so a constant whose serialized form does not match + * the name the standard defines is not a cosmetic problem: an application matching on the error + * would never see it. Because the whole point is to cover constants no other test exercises, + * the cases are generated from {@code values()} rather than listed, so a constant added later is + * covered without anyone remembering to add it here. + */ +class ErrorEnumWireFormatTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + /** Every error enum in the API, with the reader needed to deserialize it. */ + private static final Class[] ERROR_ENUMS = { + AgentError.class, + ChannelError.class, + CloseError.class, + OpenError.class, + ResolveError.class, + ResultError.class, + }; + + @TestFactory + Stream everyConstantRoundTrips() { + List tests = new ArrayList<>(); + for (Class type : ERROR_ENUMS) { + for (Object constant : type.getEnumConstants()) { + tests.add(DynamicTest.dynamicTest( + type.getSimpleName() + "." + ((Enum) constant).name(), + () -> assertRoundTrips(type, constant))); + } + } + return tests.stream(); + } + + private static void assertRoundTrips(Class type, Object constant) throws Exception { + String json = MAPPER.writeValueAsString(constant); + + // Serializing must produce the wire value, not the Java constant name, and not an + // object. Anything else means @JsonValue is missing or wrongly applied. + assertEquals("\"" + constant + "\"", json, + type.getSimpleName() + " must serialize to its wire value"); + + assertSame(constant, MAPPER.readValue(json, type), + type.getSimpleName() + " must deserialize back to the same constant"); + } + + @Test + void unknownWireValuesAreRejected() { + for (Class type : ERROR_ENUMS) { + // A Desktop Agent sending an error this version does not know about should surface + // as a clear failure rather than a null that flows on to become something stranger. + assertThrows(Exception.class, + () -> MAPPER.readValue("\"NoSuchErrorValue\"", type), + type.getSimpleName() + " must reject an unknown wire value"); + } + } + + @Test + void toStringIsTheWireValue() { + // Error enums are routinely interpolated into exception messages and logs, so a + // toString that differs from the wire value makes those unsearchable. + assertEquals("AgentNotFound", AgentError.AgentNotFound.toString()); + assertEquals("NoAppsFound", ResolveError.NoAppsFound.toString()); + assertEquals("IntentHandlerRejected", ResultError.IntentHandlerRejected.toString()); + } +} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/DesktopAgent.java b/fdc3api/src/main/java/com/finos/fdc3/api/DesktopAgent.java deleted file mode 100644 index aed70ef2..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/DesktopAgent.java +++ /dev/null @@ -1,557 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api; - -import com.finos.fdc3.api.channel.Channel; -import com.finos.fdc3.api.channel.PrivateChannel; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.AppIntent; -import com.finos.fdc3.api.metadata.AppMetadata; -import com.finos.fdc3.api.metadata.ImplementationMetadata; -import com.finos.fdc3.api.metadata.IntentResolution; -import com.finos.fdc3.api.types.AppIdentifier; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.api.types.IntentHandler; -import com.finos.fdc3.api.types.Listener; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -/** - * A Desktop Agent is a desktop component (or aggregate of components) that serves as a - * launcher and message router (broker) for applications in its domain. - * - * A Desktop Agent can be connected to one or more App Directories and will use directories for application - * identity and discovery. Typically, a Desktop Agent will contain the proprietary logic of - * a given platform, handling functionality like explicit application interop workflows where - * security, consistency, and implementation requirements are proprietary. - */ -public interface DesktopAgent { - /** - * Launches an app, specified via an `AppIdentifier` object. - * - * The `open` method differs in use from `raiseIntent`. Generally, it should be used when the target application is known but there is no specific intent. For example, if an application is querying the App Directory, `open` would be used to open an app returned in the search results. - * - * **Note**, if the intent, context and target app name are all known, it is recommended to instead use `raiseIntent` with the `target` argument. - * - * If a Context object is passed in, this object will be provided to the opened application via a contextListener. The Context argument is functionally equivalent to opening the target app with no context and broadcasting the context directly to it. - * - * Returns an `AppIdentifier` object with the `instanceId` field set identifying the instance of the application opened by this call. - * - * If an error occurs while opening the app, the promise MUST be rejected with an `Error` Object with a `message` chosen from the `OpenError` enumeration. - * - * ```javascript - * //Open an app without context, using an AppIdentifier object to specify the target by `appId`. - * let appIdentifier = {appId: 'myApp-v1.0.1'}; - * let instanceIdentifier = await fdc3.open(appIdentifier); - * - * //Open an app with context - * let instanceIdentifier = await fdc3.open(appIdentifier, context); - * ``` - */ - CompletionStage open(AppIdentifier app, Context context); - - default CompletionStage open(AppIdentifier app) { - return open(app, null); - } - - /** - * Find out more information about a particular intent by passing its name, and optionally its context and/or a desired result context type. - * - * `findIntent` is effectively granting programmatic access to the Desktop Agent's resolver. - * It returns a promise resolving to the intent, its metadata and metadata about the apps and app instances that registered that intent. - * This can be used to raise the intent against a specific app or app instance. - * - * If the resolution fails, the promise MUST be rejected with an `Error` Object with a `message` chosen from the `ResolveError` enumeration. This includes the case where no apps are found that resolve the intent, when the `ResolveError.NoAppsFound` message should be used. - * - * Result types may be a type name, the string "channel" (which indicates that the app - * will return a channel) or a string indicating a channel that returns a specific type, - * e.g. "channel". - * - * If intent resolution to an app returning a channel is requested, the desktop agent - * MUST include both apps that are registered as returning a channel and those registered - * as returning a channel with a specific type in the response. - * - * ```javascript - * // I know 'StartChat' exists as a concept, and want to know which apps can resolve it ... - * const appIntent = await fdc3.findIntent("StartChat"); - * - * // returns a single AppIntent: - * // { - * // intent: { name: "StartChat", displayName: "Chat" }, - * // apps: [ - * // { appId: "Skype" }, - * // { appId: "Symphony" }, - * // { appId: "Slack" } - * // ] - * // } - * - * // raise the intent against a particular app - * await fdc3.raiseIntent(appIntent.intent.name, context, appIntent.apps[0]); - * - * //later, we want to raise 'StartChat' intent again - * const appIntent = await fdc3.findIntent("StartChat"); - * // returns an AppIntent, but with multiple options for resolution, - * // which includes an existing instance of an application: - * // { - * // intent: { name: "StartChat", displayName: "Chat" }, - * // apps: [ - * // { appId: "Skype" }, - * // { appId: "Symphony" }, - * // { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" }, - * // { appId: "Slack" } - * // ] - * ``` - * - * An optional input context object and result type may be specified, which the resolver MUST use to filter the returned applications such that each supports the specified input and result types. - * - * ```javascript - * const appIntent = await fdc3.findIntent("StartChat", contact); - * - * // returns only apps that support the type of the specified input context: - * // { - * // intent: { name: "StartChat", displayName: "Chat" }, - * // apps: [{ appId: "Symphony" }] - * // } - * - * const appIntent = await fdc3.findIntent("ViewContact", contact, "fdc3.ContactList"); - * - * // returns only apps that return the specified result Context type: - * // { - * // intent: { name: "ViewContact", displayName: "View Contact Details" }, - * // apps: { appId: "MyCRM", resultType: "fdc3.ContactList"}] - * // } - * - * const appIntent = await fdc3.findIntent("QuoteStream", instrument, "channel"); - * - * // returns only apps that return a channel which will receive the specified input and result types: - * // { - * // intent: { name: "QuoteStream", displayName: "Quotes stream" }, - * // apps: [{ appId: "MyOMS", resultType: "channel"}] - * // } - * ``` - */ - CompletionStage findIntent(String indent, Context context, String resultType); - - default CompletionStage findIntent(String indent, Context context) { - return findIntent(indent, context, null); - } - - default CompletionStage findIntent(String indent) { - return findIntent(indent, null); - } - - /** - * Find all the available intents for a particular context, and optionally a desired result context type. - * - * `findIntentsByContext` is effectively granting programmatic access to the Desktop Agent's resolver. - * It returns a promise resolving to an `AppIntent` which provides details of the intent, its metadata and metadata about the apps and app instances that are registered to handle it. This can be used to raise the intent against a specific app or app instance. - * - * If the resolution fails, the promise MUST be rejected with an `Error` Object with a `message` chosen from the `ResolveError` enumeration. This includes the case where no intents with associated apps are found, when the `ResolveError.NoAppsFound` message should be used. - * - * The optional `resultType` argument may be a type name, the string "channel" (which indicates that the app - * should return a channel) or a string indicating a channel that returns a specific type, - * e.g. "channel". If intent resolution to an app returning a channel is requested without - * a specified context type, the desktop agent MUST also include apps that are registered as returning a - * channel with a specific type in the response. - * - * ```javascript - * // I have a context object, and I want to know what I can do with it, hence, I look for intents and apps to resolve them... - * const appIntents = await fdc3.findIntentsByContext(context); - * - * // returns for example: - * // [ - * // { - * // intent: { name: "StartCall", displayName: "Call" }, - * // apps: [{ name: "Skype" }] - * // }, - * // { - * // intent: { name: "StartChat", displayName: "Chat" }, - * // apps: [ - * // { appId: "Skype" }, - * // { appId: "Symphony" }, - * // { appId: "Symphony", instanceId: "93d2fe3e-a66c-41e1-b80b-246b87120859" }, - * // { appId: "Slack" } - * // ] - * // } - * // ]; - * - * // or I look for only intents that are resolved by apps returning a particular result type - * const appIntentsForType = await fdc3.findIntentsByContext(context, "fdc3.ContactList"); - * // returns for example: - * // [{ - * // intent: { name: "ViewContact", displayName: "View Contacts" }, - * // apps: [{ appId: "MyCRM", resultType: "fdc3.ContactList"}] - * // }]; - * - * // select a particular intent to raise - * const resolvedIntent = appIntents[1]; - * - * // target a particular app or instance - * const selectedApp = resolvedIntent.apps[2]; - * - * // raise the intent, passing the given context, targeting the app or app instance - * await fdc3.raiseIntent(startChat.intent.name, context, selectedApp); - * ``` - */ - CompletionStage> findIntentsByContext(Context context, String resultType); - - default CompletionStage> findIntentsByContext(Context context) { - return findIntentsByContext(context, null); - } - - /** - * Find all the available instances for a particular application. - * - * If there are no instances of the specified application the returned promise should resolve to an empty array. - * - * If the request fails for another reason, the promise MUST be rejected with an `Error` Object with a `message` chosen from the `ResolveError` enumeration. - * - * ```javascript - * // Retrieve a list of instances of an application - * let instances = await fdc3.findInstances({appId: "MyAppId"}); - * - * // Target a raised intent at a specific instance - * let resolution = fdc3.raiseIntent("ViewInstrument", context, instances[0]); - * ``` - * @param app - */ - CompletionStage> findInstances(AppIdentifier app); - - /** - * Publishes context to other apps on the desktop. Calling `broadcast` at the `DesktopAgent` scope will push the context to whatever _User Channel_ the app is joined to. If the app is not currently joined to a channel, calling `fdc3.broadcast` will have no effect. Apps can still directly broadcast and listen to context on any channel via the methods on the `Channel` class. - * - * DesktopAgent implementations should ensure that context messages broadcast to a channel by an application joined to it should not be delivered back to that same application. - * - * If you are working with complex context types composed of other simpler types then you should broadcast - * each individual type (starting with the simpler types, followed by the complex type) that you want other - * apps to be able to respond to. Doing so allows applications to filter the context types they receive by - * adding listeners for specific context types. - * - * ```javascript - * const instrument = { - * type: 'fdc3.instrument', - * id: { - * ticker: 'AAPL' - * } - * }; - * fdc3.broadcast(context); - * ``` - */ - CompletionStage broadcast(Context context); - - /** - * Raises a specific intent for resolution against apps registered with the desktop agent. - * - * The desktop agent MUST resolve the correct app to target based on the provided intent name and context data. If multiple matching apps are found, the user MAY be presented with a Resolver UI allowing them to pick one, or another method of Resolution applied to select an app. - * Alternatively, the specific app or app instance to target can also be provided. A list of valid target applications and instances can be retrieved via `findIntent`. - * - * If a target app for the intent cannot be found with the criteria provided or the user either closes the resolver UI or otherwise cancels resolution, the promise MUST be rejected with an `Error` object with a `message` chosen from the `ResolveError` enumeration. If a specific target `app` parameter was set, but either the app or app instance is not available, the promise MUST be rejected with an `Error` object with either the `ResolveError.TargetAppUnavailable` or `ResolveError.TargetInstanceUnavailable` string as its `message`. - * - * If you wish to raise an Intent without a context, use the `fdc3.nothing` context type. This type exists so that apps can explicitly declare support for raising an intent without context. - * - * Returns an `IntentResolution` object with details of the app instance that was selected (or started) to respond to the intent. - * - * Issuing apps may optionally wait on the promise that is returned by the `getResult()` member of the `IntentResolution`. This promise will resolve when the _receiving app's_ intent handler function returns and resolves a promise. The Desktop Agent resolves the issuing app's promise with the Context object or Channel that is provided as resolution within the receiving app. The Desktop Agent MUST reject the issuing app's promise, with a string from the `ResultError` enumeration, if: (1) the intent handling function's returned promise rejects, (2) the intent handling function doesn't return a promise, or (3) the returned promise resolves to an invalid type. - * - * ```javascript - * // raise an intent for resolution by the desktop agent - * // a resolver UI may be displayed if more than one application can resolve the intent - * await fdc3.raiseIntent("StartChat", context); - * - * // or find apps to resolve an intent to start a chat with a given contact - * const appIntent = await fdc3.findIntent("StartChat", context); - * // use the metadata of an app or app instance to describe the target app for the intent - * await fdc3.raiseIntent("StartChat", context, appIntent.apps[0]); - * - * //Raise an intent without a context by using the null context type - * await fdc3.raiseIntent("StartChat", {type: "fdc3.nothing"}); - * - * //Raise an intent and retrieve a result from the IntentResolution - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { //detect whether the result is Context or a Channel - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return anything` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * ``` - */ - CompletionStage raiseIntent(String intent, Context context, AppIdentifier app); - - default CompletionStage raiseIntent(String intent, Context context) { - return raiseIntent(intent, context, null); - } - - /** - * Finds and raises an intent against apps registered with the desktop agent based on the type of the specified context data example. - * - * The desktop agent SHOULD first resolve to a specific intent based on the provided context if more than one intent is available for the specified context. This MAY be achieved by displaying a resolver UI. It SHOULD then resolve to a specific app to handle the selected intent and specified context. - * Alternatively, the specific app or app instance to target can also be provided, in which case the resolver SHOULD only offer intents supported by the specified application. - * - * Using `raiseIntentForContext` is similar to calling `findIntentsByContext`, and then raising an intent against one of the returned apps, except in this case the desktop agent has the opportunity to provide the user with a richer selection interface where they can choose both the intent and target app. - * - * Returns an `IntentResolution` object, see `raiseIntent()` for details. - * - * If a target intent and app cannot be found with the criteria provided or the user either closes the resolver UI or otherwise cancels resolution, the promise MUST be rejected with an `Error` object with a `message` chosen from the `ResolveError` enumeration. If a specific target `app` parameter was set, but either the app or app instance is not available, the promise MUST be rejected with an `Error` object with either the `ResolveError.TargetAppUnavailable` or `ResolveError.TargetInstanceUnavailable` string as its `message`. - * - * ```javascript - * // Resolve against all intents registered for the type of the specified context - * await fdc3.raiseIntentForContext(context); - * - * // Resolve against all intents registered by a specific target app for the specified context - * await fdc3.raiseIntentForContext(context, targetAppIdentifier); - * ``` - */ - CompletionStage raiseIntentForContext(Context context, AppIdentifier app); - - default CompletionStage raiseIntentForContext(Context context) { - return raiseIntentForContext(context, null); - } - - /** - * Adds a listener for incoming Intents from the Agent. The handler function may return void or a promise that should resolve to an `IntentResult`, which is either a `Context` object, representing any data that should be returned, or a `Channel` over which data responses will be sent. The IntentResult will be returned to app that raised the intent via the `IntentResolution` and retrieved from it using the `getResult()` function. - * - * The Desktop Agent MUST reject the promise returned by the `getResult()` function of `IntentResolution` if: (1) the intent handling function's returned promise rejects, (2) the intent handling function doesn't return a promise, or (3) the returned promise resolves to an invalid type. - * - * The `PrivateChannel` type is provided to support synchronisation of data transmitted over returned channels, by allowing both parties to listen for events denoting subscription and unsubscription from the returned channel. `PrivateChannels` are only retrievable via raising an intent. - * - * Optional metadata about the raised intent, including the app that originated the message, SHOULD be provided by the desktop agent implementation. - * - * ```javascript - * //Handle a raised intent - * const listener = fdc3.addIntentListener('StartChat', context => { - * // start chat has been requested by another application - * return; - * }); - * - * //Handle a raised intent and log the originating app metadata - * const listener = fdc3.addIntentListener('StartChat', (contact, metadata) => { - * console.log(`Received intent StartChat\nContext: ${contact}\nOriginating app: ${metadata?.source}`); - * return; - * }); - * - * //Handle a raised intent and return Context data via a promise - * fdc3.addIntentListener("CreateOrder", (context) => { - * return new Promise((resolve) => { - * // go create the order - * resolve({type: "fdc3.order", id: { "orderId": 1234}}); - * }); - * }); - * - * //Handle a raised intent and return a Private Channel over which response will be sent - * fdc3.addIntentListener("QuoteStream", async (context) => { - * const channel: PrivateChannel = await fdc3.createPrivateChannel(); - * const symbol = context.id.symbol; - * - * // Called when the remote side adds a context listener - * const addContextListener = channel.onAddContextListener((contextType) => { - * // broadcast price quotes as they come in from our quote feed - * feed.onQuote(symbol, (price) => { - * channel.broadcast({ type: "price", price}); - * }); - * }); - * - * // Stop the feed if the remote side closes - * const disconnectListener = channel.onDisconnect(() => { - * feed.stop(symbol); - * }); - * - * return channel; - * }); - * ``` - */ - CompletionStage addIntentListener(String intent, IntentHandler handler); - - /** - * Adds a listener for incoming context broadcasts from the Desktop Agent via User channels. If the consumer is only interested in a context of a particular type, they can they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. - * - * Context broadcasts are only received from apps that are joined to the same User channel as the listening application, hence, if the application is not currently joined to a channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. - * - * Optional metadata about the context message, including the app that originated the message, SHOULD be provided by the desktop agent implementation. - * - * ```javascript - * // any context - * const listener = await fdc3.addContextListener(null, context => { ... }); - * - * // listener for a specific type - * const contactListener = await fdc3.addContextListener('fdc3.contact', contact => { ... }); - * - * // listener that logs metadata for the message a specific type - * const contactListener = await fdc3.addContextListener('fdc3.contact', (contact, metadata) => { - * console.log(`Received context message\nContext: ${contact}\nOriginating app: ${metadata?.source}`); - * //do something else with the context - * }); - * ``` - */ - CompletionStage addContextListener(String contextType, ContextHandler handler); - - /** - * Retrieves a list of the User channels available for the app to join. - */ - CompletionStage> getUserChannels(); - - /** - * Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the desktop agent, rather than calling this function directly. - * - * If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. - * - * If the channel already contains context that would be passed to context listeners assed via `fdc3.addContextListener` then those listeners will be called immediately with that context. - * - * An app can only be joined to one channel at a time. - * - * If an error occurs (such as the channel is unavailable or the join request is denied) the promise MUST be rejected with an `Error` Object with a `message` chosen from the `ChannelError` enumeration. - * - * ```javascript - * // get all system channels - * const channels = await fdc3.getUserChannels(); - * // create UI to pick from the User channels - * // join the channel on selection - * fdc3.joinUserChannel(selectedChannel.id); - * ``` - */ - CompletionStage joinUserChannel(String channelId); - - /** - * Returns a `Channel` object for the specified channel, creating it (as an _App_ channel) if it does not exist. - * - * If the Channel cannot be created or access was denied, the returned promise MUST be rejected with an `Error` Object with a `message` chosen from the `ChannelError` enumeration. - * - * ```javascript - * try { - * const myChannel = await fdc3.getOrCreateChannel("myChannel"); - * const myChannel.addContextListener(null, context => {}); - * } - * catch (err){ - * //app could not register the channel - * } - * ``` - */ - CompletionStage getOrCreateChannel(String channelId); - - /** - * Returns a `Channel` with an auto-generated identity that is intended for private communication between applications. Primarily used to create Channels that will be returned to other applications via an `IntentResolution` for a raised intent. - * - * If the `PrivateChannel` cannot be created, the returned promise MUST be rejected with an `Error` object with a `message` chosen from the `ChannelError` enumeration. - * - * The `PrivateChannel` type is provided to support synchronisation of data transmitted over returned channels, by allowing both parties to listen for events denoting subscription and unsubscription from the returned channel. `PrivateChannels` are only retrievable via raising an intent. - * - * * It is intended that Desktop Agent implementations: - * - SHOULD restrict external apps from listening or publishing on this channel. - * - MUST prevent `PrivateChannels` from being retrieved via fdc3.getOrCreateChannel. - * - MUST provide the `id` value for the channel as required by the `Channel` interface. - * - * ```javascript - * fdc3.addIntentListener("QuoteStream", async (context) => { - * const channel: PrivateChannel = await fdc3.createPrivateChannel(); - * const symbol = context.id.ticker; - * - * // This gets called when the remote side adds a context listener - * const addContextListener = channel.onAddContextListener((contextType) => { - * // broadcast price quotes as they come in from our quote feed - * feed.onQuote(symbol, (price) => { - * channel.broadcast({ type: "price", price}); - * }); - * }); - * - * // This gets called when the remote side calls Listener.unsubscribe() - * const unsubscriberListener = channel.onUnsubscribe((contextType) => { - * feed.stop(symbol); - * }); - * - * // This gets called if the remote side closes - * const disconnectListener = channel.onDisconnect(() => { - * feed.stop(symbol); - * }) - * - * return channel; - * }); - * ``` - */ - CompletionStage createPrivateChannel(); - - /** - * Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. - * - * Returns `null` if the app is not joined to a channel. - */ - CompletionStage> getCurrentChannel(); - - /** - * Optional function that removes the app from any User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. - * - * Context broadcast and listening through the top-level `fdc3.broadcast` and `fdc3.addContextListener` will be a no-op when the app is not on a channel. - * - * ```javascript - * //desktop-agent scope context listener - * const fdc3Listener = fdc3.addContextListener(null, context => {}); - * await fdc3.leaveCurrentChannel(); - * //the fdc3Listener will now cease receiving context - * //listening on a specific channel, retrieved via fdc3.getOrCreateChannel(), will continue to work: - * redChannel.addContextListener(null, channelListener); - * ``` - */ - CompletionStage leaveCurrentChannel(); - - /** - * Retrieves information about the FDC3 Desktop Agent implementation, including the supported version - * of the FDC3 specification, the name of the provider of the implementation, its own version number - * and the metadata of the calling application according to the desktop agent. - * - * Returns an `ImplementationMetadata` object. This metadata object can be used to vary the behavior - * of an application based on the version supported by the Desktop Agent and for logging purposes. - * - * ```js - * import {compareVersionNumbers, versionIsAtLeast} from '@finos/fdc3'; - * - * if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), "1.2")) { - * await fdc3.raiseIntentForContext(context); - * } else { - * await fdc3.raiseIntent("ViewChart", context); - * } - * ``` - * - * The `ImplementationMetadata` object returned also includes the metadata for the calling application, - * according to the Desktop Agent. This allows the application to retrieve its own `appId`, `instanceId` - * and other details, e.g.: - * - * ```js - * let implementationMetadata = await fdc3.getInfo(); - * let {appId, instanceId} = implementationMetadata.appMetadata; - * ``` - */ - CompletionStage getInfo(); - - /** - * Retrieves the `AppMetadata` for an `AppIdentifier`, which provides additional metadata (such as icons, - * a title and description) from the App Directory record for the application, that may be used for display - * purposes. - * - * ```js - * let appIdentifier = { appId: "MyAppId@my.appd.com" } - * let appMetadata = await fdc3.getAppMetadata(appIdentifier); - * ``` - */ - CompletionStage getAppMetadata(AppIdentifier app); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/channel/PrivateChannel.java b/fdc3api/src/main/java/com/finos/fdc3/api/channel/PrivateChannel.java deleted file mode 100644 index cb2c8c41..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/channel/PrivateChannel.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.channel; - -import java.util.Optional; -import java.util.function.Consumer; - -import com.finos.fdc3.api.types.Listener; - -/** - * Object representing a private context channel, which is intended to support secure communication between applications, and - * extends the Channel interface with event handlers which provide information on the connection state of both parties, ensuring - * that desktop agents do not need to queue or retain messages that are broadcast before a context listener is added and that - * applications are able to stop broadcasting messages when the other party has disconnected. It is intended that Desktop Agent - * implementations: - SHOULD restrict external apps from listening or publishing on this channel. - MUST prevent private channels - * from being retrieved via fdc3.getOrCreateChannel. - MUST provide the `id` value for the channel as required by the Channel - * interface. - */ -public interface PrivateChannel extends Channel { - /** - * Adds a listener that will be called each time that the remote app invokes addContextListener on this channel. Desktop Agents - * MUST call this for each invocation of addContextListener on this channel, including those that occurred before this handler - * was registered (to prevent race conditions). - */ - Listener onAddContextListener(Consumer> handler); - - /** - * Adds a listener that will be called whenever the remote app invokes Listener.unsubscribe() on a context listener that it - * previously added. Desktop Agents MUST call this when disconnect() is called by the other party, for each listener that they - * have added. - */ - Listener onUnsubsrcibe(Consumer> handler); - - /** - * Adds a listener that will be called when the remote app terminates, for example when its window is closed or because - * disconnect was called. This is in addition to calls that will be made to onUnsubscribe listeners. - */ - Listener onDisconnect(Runnable handler); - - /** - * May be called to indicate that a participant will no longer interact with this channel. After this function has been called, - * Desktop Agents SHOULD prevent apps from broadcasting on this channel and MUST automatically call Listener.unsubscribe() for - * each listener that they've added (causing any onUnsubscribe handler added by the other party to be called) before triggering - * any onDisconnect handler added by the other party. - */ - void disconnect(); - - @Override - default Type getType() { - - return Type.Private; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Chart.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Chart.java deleted file mode 100644 index 708f8b44..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Chart.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.List; -import java.util.Set; - -@JsonPropertyOrder({ - "type", - "instruments", - "range", - "style", - "otherConfig" -}) -public class Chart extends Context { - public static String TYPE = "fdc3.chart"; - public static Set STYLE = Set.of("line", "bar", "stacked-bar", "mountain", "candle", "pie", "scatter", "histogram", "heatmap", "custom"); - - @JsonProperty("instruments") - private List instruments; - - @JsonProperty("range") - private TimeRange range; - - @JsonProperty("style") - private String style; - - @JsonProperty("otherConfig") - private Object otherConfig; - - public Chart(List instruments) { - super(TYPE); - this.instruments = instruments; - } - - public List getInstruments() { - return instruments; - } - - public void setInstruments(List instruments) { - this.instruments = instruments; - } - - public TimeRange getRange() { - return range; - } - - public void setRange(TimeRange range) { - this.range = range; - } - - public String getStyle() { - return style; - } - - public void setStyle(String style) { - if(!STYLE.contains(style)) { - throw new IllegalArgumentException("Invalid Style argument!"); - } - this.style = style; - } - - public Object getOtherConfig() { - return otherConfig; - } - - public void setOtherConfig(Object otherConfig) { - this.otherConfig = otherConfig; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/ChatInitSettings.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/ChatInitSettings.java deleted file mode 100644 index bdcfe578..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/ChatInitSettings.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonPropertyOrder({ - "type", - "chatName", - "members", - "initMessage", - "options" -}) -public class ChatInitSettings extends Context { - public static String TYPE = "fdc3.chat.initSettings"; - - @JsonProperty("chatName") - private String chatName; - - @JsonProperty("members") - private ContactList members; - - @JsonProperty("initMessage") - private String initMessage; - - @JsonProperty("options") - private Options options; - - public ChatInitSettings() { - super(TYPE); - } - - public String getChatName() { - return chatName; - } - - public void setChatName(String chatName) { - this.chatName = chatName; - } - - public ContactList getMembers() { - return members; - } - - public void setMembers(ContactList members) { - this.members = members; - } - - public String getInitMessage() { - return initMessage; - } - - public void setInitMessage(String initMessage) { - this.initMessage = initMessage; - } - - public Options getOptions() { - return options; - } - - public void setOptions(Options options) { - this.options = options; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Contact.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Contact.java deleted file mode 100644 index e0705abb..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Contact.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.Map; - -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Contact extends Context { - public static String TYPE = "fdc3.contact"; - public static Map VALID_ID_KEYS = Map.of( - "email", false, - "FDS_ID", false); - - public Contact() { - super(TYPE); - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContactList.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/ContactList.java deleted file mode 100644 index ae56c8b4..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContactList.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.List; - -@JsonPropertyOrder({ - "type", - "name", - "id", - "contacts" -}) -public class ContactList extends Context { - public static String TYPE = "fdc3.contactList"; - - @JsonProperty("contacts") - private List contacts; - - public ContactList(List contacts) { - super(TYPE); - this.contacts = contacts; - } - - public List getContacts() { - return contacts; - } - - public void setContacts(List contacts) { - this.contacts = contacts; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Context.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Context.java deleted file mode 100644 index c4a48479..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Context.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.finos.fdc3.api.utils.StringUtilities; - -import java.util.Map; - -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Context -{ - @JsonProperty("type") - private String type; - - @JsonProperty("name") - private String name; - - @JsonProperty("id") - private Map id; - - public Context() {} - public Context(String type) { - this.type = type; - this.name = null; - this.id = null; - } - - public Context(String type, String name) { - this.type = type; - this.name = name; - this.id = null; - } - - public Context(String type, Map id) { - this.type = type; - this.name = null; - this.setId(id); - } - - public Context(String type, String name, Map id) { - this.type = type; - this.name = name; - this.setId(id); - } - - public String getType() - { - return type; - } - - public Map getId() - { - return id; - } - - public void setId(Map id) - { - /* - Map keyMap = ContextContants.CONTEXT_ID_KEYS_MAPPING.getOrDefault(type, null); - if(!ContextHelper.hasValidKeys(id, keyMap)) { - throw new IllegalArgumentException("Invalid ID(s) present!"); - } - if(!ContextHelper.hasMandatoryKeys(id, keyMap)) { - throw new IllegalArgumentException("Mandatory ID(s) missing!"); - } - */ - - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - @Override - public String toString() - { - return StringUtilities.valueAsString(this); - } - -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextContants.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextContants.java deleted file mode 100644 index 73752230..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextContants.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import java.util.Collections; -import java.util.Map; - -public class ContextContants { - - - public static Map> CONTEXT_ID_KEYS_MAPPING = Map.of( - Contact.TYPE, Contact.VALID_ID_KEYS, - Country.TYPE, Country.VALID_ID_KEYS, - Currency.TYPE, Currency.VALID_ID_KEYS, - Instrument.TYPE, Instrument.VALID_ID_KEYS, - Organization.TYPE, Organization.VALID_ID_KEYS, - ContactList.TYPE, Collections.emptyMap(), - InstrumentList.TYPE, Collections.emptyMap() - ); - -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextHelper.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextHelper.java deleted file mode 100644 index a5898e74..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/ContextHelper.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class ContextHelper { - public static Set getMandatoryIdKeys(Map validIdKeys) { - Set mandatoryIdKeys = new HashSet<>(); - if(validIdKeys == null) { - return mandatoryIdKeys; - } - for(Map.Entry entry : validIdKeys.entrySet()) { - if(entry.getValue()) { - mandatoryIdKeys.add(entry.getKey()); - } - } - return mandatoryIdKeys; - } - - public static boolean hasMandatoryKeys(Map idMap, Map validIdKeys) { - Set mandatoryIdKeys = ContextHelper.getMandatoryIdKeys(validIdKeys); - if(mandatoryIdKeys.isEmpty()) { - return true; - } else if (idMap == null) { - return false; - } - for(Object key : mandatoryIdKeys) { - if(!idMap.containsKey(key)) { - return false; - } - } - return true; - } - - public static boolean hasValidKeys(Map idMap, Map validIdKeys) { - if (idMap == null) { - return true; - } - if (validIdKeys == null) { - return false; - } - if (validIdKeys.isEmpty()) { - return true; - } - for(Object key: idMap.keySet()) { - if(!validIdKeys.containsKey(key)) { - return false; - } - } - return true; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Country.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Country.java deleted file mode 100644 index 45f5b56e..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Country.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Country extends Context { - public static String TYPE = "fdc3.country"; - public static Map VALID_ID_KEYS = Map.of("COUNTRY_ISOALPHA2", true, "COUNTRY_ISOALPHA3", false, "ISOALPHA2", false, "ISOALPHA3", false); - - public Country(Map id, String name) { - super(TYPE, name, id); - } - - public Country(Map id) { - super(TYPE, id); - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Email.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Email.java deleted file mode 100644 index 26ba765b..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Email.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonPropertyOrder({ - "type", - "recipients", - "subject", - "textBody" -}) -public class Email extends Context { - public static String TYPE = "fdc3.email"; - - @JsonProperty("recipients") - private ContactList recipients; - - @JsonProperty("subject") - private String subject; - - @JsonProperty("textBody") - private String textBody; - - public Email(ContactList recipients) { - super(TYPE); - this.recipients = recipients; - } - - public ContactList getRecipients() { - return recipients; - } - - public void setRecipients(ContactList recipients) { - this.recipients = recipients; - } - - public String getSubject() { - return subject; - } - - public void setSubject(String subject) { - this.subject = subject; - } - - public String getTextBody() { - return textBody; - } - - public void setTextBody(String textBody) { - this.textBody = textBody; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Instrument.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Instrument.java deleted file mode 100644 index 0822d9af..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Instrument.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.Map; - -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Instrument extends Context { - public static String TYPE = "fdc3.instrument"; - public static Map VALID_ID_KEYS = Map.of( - "FDS_ID", false, - "PERMID", false, - "RIC", false, - "BBG", false, - "ticker", false, - "FIGI", false, - "ISIN", false, - "CUSIP", false, - "SEDOL", false); - - public Instrument() { - super(TYPE); - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/InstrumentList.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/InstrumentList.java deleted file mode 100644 index 7e1bef4c..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/InstrumentList.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.List; - -@JsonPropertyOrder({ - "type", - "name", - "id", - "instruments" -}) -public class InstrumentList extends Context { - public static String TYPE = "fdc3.instrumentList"; - - @JsonProperty("instruments") - private List instruments; - - public InstrumentList(List instruments) { - super(TYPE); - this.instruments = instruments; - } - - public List getInstruments() { - return instruments; - } - - public void setInstruments(List instruments) { - this.instruments = instruments; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Options.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Options.java deleted file mode 100644 index f0863b7e..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Options.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonPropertyOrder({ - "groupRecipients", - "public", - "allowHistoryBrowsing", - "allowMessageCopy", - "allowAddUser", -}) -public class Options { - @JsonProperty("groupRecipients") - private boolean groupRecipients; - - @JsonProperty("public") - private boolean publicFlag; - - @JsonProperty("allowHistoryBrowsing") - private boolean allowHistoryBrowsing; - - @JsonProperty("allowMessageCopy") - private boolean allowMessageCopy; - - @JsonProperty("allowAddUser") - private boolean allowAddUser; - - public Options() { - this.groupRecipients = false; - this.publicFlag = false; - this.allowHistoryBrowsing = false; - this.allowMessageCopy = false; - this.allowAddUser = false; - } - - public boolean isGroupRecipients() { - return groupRecipients; - } - - public void setGroupRecipients(boolean groupRecipients) { - this.groupRecipients = groupRecipients; - } - - public boolean isPublicFlag() { - return publicFlag; - } - - public void setPublicFlag(boolean publicFlag) { - this.publicFlag = publicFlag; - } - - public boolean isAllowHistoryBrowsing() { - return allowHistoryBrowsing; - } - - public void setAllowHistoryBrowsing(boolean allowHistoryBrowsing) { - this.allowHistoryBrowsing = allowHistoryBrowsing; - } - - public boolean isAllowMessageCopy() { - return allowMessageCopy; - } - - public void setAllowMessageCopy(boolean allowMessageCopy) { - this.allowMessageCopy = allowMessageCopy; - } - - public boolean isAllowAddUser() { - return allowAddUser; - } - - public void setAllowAddUser(boolean allowAddUser) { - this.allowAddUser = allowAddUser; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Organization.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Organization.java deleted file mode 100644 index d288e629..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Organization.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.Map; - -@JsonPropertyOrder({ - "type", - "name", - "id" -}) -public class Organization extends Context { - public static String TYPE = "fdc3.organization"; - public static Map VALID_ID_KEYS = Map.of( - "LEI", false, - "PERMID", false, - "FDS_ID", false); - - public Organization() { - super(TYPE); - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Portfolio.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Portfolio.java deleted file mode 100644 index 9464ef33..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Portfolio.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.List; - -@JsonPropertyOrder({ - "type", - "id", - "name", - "positions" -}) -public class Portfolio extends Context { - public static String TYPE = "fdc3.portfolio"; - - @JsonProperty("positions") - private List positions; - - public Portfolio(List positions) { - super(TYPE); - this.positions = positions; - } - - public List getPositions() { - return positions; - } - - public void setPositions(List positions) { - this.positions = positions; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Position.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Position.java deleted file mode 100644 index b62cc0c0..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Position.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.math.BigDecimal; - -@JsonPropertyOrder({ - "type", - "id", - "name", - "holding", - "instrument" -}) -public class Position extends Context { - public static String TYPE = "fdc3.position"; - - @JsonProperty("holding") - private BigDecimal holding; - - @JsonProperty("instrument") - private Instrument instrument; - - public Position(BigDecimal holding, Instrument instrument) { - super(TYPE); - this.holding = holding; - this.instrument = instrument; - } - - public BigDecimal getHolding() { - return holding; - } - - public void setHolding(BigDecimal holding) { - this.holding = holding; - } - - public Instrument getInstrument() { - return instrument; - } - - public void setInstrument(Instrument instrument) { - this.instrument = instrument; - } -} \ No newline at end of file diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/TimeRange.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/TimeRange.java deleted file mode 100644 index e8e0b3f1..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/TimeRange.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import org.joda.time.DateTime; - -@JsonPropertyOrder({ - "type", - "startTime", - "endTime" -}) -public class TimeRange extends Context { - public static String TYPE = "fdc3.timeRange"; - - @JsonProperty("startTime") - private DateTime startTime; - - @JsonProperty("endTime") - private DateTime endTime; - - public TimeRange() { - super(TYPE); - } - - public DateTime getStartTime() { - return startTime; - } - - public void setStartTime(DateTime startTime) { - this.startTime = startTime; - } - - public DateTime getEndTime() { - return endTime; - } - - public void setEndTime(DateTime endTime) { - this.endTime = endTime; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/context/Valuation.java b/fdc3api/src/main/java/com/finos/fdc3/api/context/Valuation.java deleted file mode 100644 index 6023f212..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/context/Valuation.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.context; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import org.joda.time.DateTime; - -@JsonPropertyOrder({ - "type", - "value", - "price", - "CURRENCY_ISOCODE", - "valuationTime", - "expiryTime" -}) -public class Valuation extends Context { - public static String TYPE = "fdc3.valuation"; - - @JsonProperty("value") - private Double value; - - @JsonProperty("price") - private Double price; - - @JsonProperty("CURRENCY_ISOCODE") - private String currencyIsocode; - - @JsonProperty("valuationTime") - private DateTime valuationTime; - - @JsonProperty("expiryTime") - private DateTime expiryTime; - - public Valuation(Double value, String currencyIsocode) { - super(TYPE); - this.value = value; - this.currencyIsocode = currencyIsocode; - } - - public Double getValue() { - return value; - } - - public void setValue(Double value) { - this.value = value; - } - - public Double getPrice() { - return price; - } - - public void setPrice(Double price) { - this.price = price; - } - - public String getCurrencyIsocode() { - return currencyIsocode; - } - - public void setCurrencyIsocode(String currencyIsocode) { - this.currencyIsocode = currencyIsocode; - } - - public DateTime getValuationTime() { - return valuationTime; - } - - public void setValuationTime(DateTime valuationTime) { - this.valuationTime = valuationTime; - } - - public DateTime getExpiryTime() { - return expiryTime; - } - - public void setExpiryTime(DateTime expiryTime) { - this.expiryTime = expiryTime; - } -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ChannelError.java b/fdc3api/src/main/java/com/finos/fdc3/api/errors/ChannelError.java deleted file mode 100644 index b274127d..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ChannelError.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.errors; - -public enum ChannelError -{ - NoChannelFound("NoChannelFound"), - AccessDenied("AccessDenied"), - CreationFailed("CreationFailed"); -private final String value; - -private ChannelError(String value) -{ - this.value = value; -} - -public String toString() -{ - return this.value; -} -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/errors/OpenError.java b/fdc3api/src/main/java/com/finos/fdc3/api/errors/OpenError.java deleted file mode 100644 index 223e860a..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/errors/OpenError.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.errors; - -public enum OpenError -{ - AppNotFound("AppNotFound"), - ErrorOnLaunch("ErrorOnLaunch"), - AppTimeout("AppTimeout"), - ResolverUnavailable("ResolverUnavailable"); - private final String value; - -private OpenError(String value) -{ - this.value = value; -} - -public String toString() -{ - return this.value; -} -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResolveError.java b/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResolveError.java deleted file mode 100644 index 3e70a862..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResolveError.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.errors; - -public enum ResolveError -{ - NoAppsFound("NoAppsFound"), - ResolverUnavailable("ResolverUnavailable"), - UserCancelled("UserCancelledResolution"), - ResolverTimeout("ResolverTimeout"), - TargetAppUnavailable("TargetAppUnavailable"), - TargetInstanceUnavailable("TargetInstanceUnavailable"), - IntentDeliveryFailed("IntentDeliveryFailed"); -private final String value; - -private ResolveError(String value) -{ - this.value = value; -} - -public String toString() -{ - return this.value; -} -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResultError.java b/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResultError.java deleted file mode 100644 index 0c37a229..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/errors/ResultError.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.errors; - -public enum ResultError -{ - NoResultReturned("NoResultReturned"), - IntentHandlerRejected("IntentHandlerRejected"); -private final String value; - -private ResultError(String value) -{ - this.value = value; -} - -public String toString() -{ - return this.value; -} -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppMetadata.java b/fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppMetadata.java deleted file mode 100644 index 292727bf..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/AppMetadata.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.metadata; - -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -import com.finos.fdc3.api.types.AppIdentifier; - -/** - * Extends an `AppIdentifier`, describing an application or instance of an application, with additional descriptive metadata that is usually provided by an FDC3 App Directory that the desktop agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such as a launcher menu or resolver UI. This includes a title, description, tooltip and icon and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. - */ -public interface AppMetadata extends AppIdentifier -{ - /** - The 'friendly' app name. - This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now require an `AppIdentifier` wth `appId` set. - Note that for display purposes the `title` field should be used, if set, in preference to this field. - */ - public Optional getName(); - - /** The Version of the application. */ - public Optional getVersion(); - - /** An optional set of, implementation specific, metadata fields that can be used to disambiguate instances, such as a window title or screen position. Must only be set if `instanceId` is set. */ - public Optional> getInstanceMetadata(); - - /** A more user-friendly application title that can be used to render UI elements */ - public Optional getTitle(); - - /** A tooltip for the application that can be used to render UI elements */ - public Optional getTooltip(); - - /** A longer, multi-paragraph description for the application that could include markup */ - public Optional getDescription(); - - /** A list of icon URLs for the application that can be used to render UI elements - * @return*/ - public Optional> getIcons(); - - /** Images representing the app in common usage scenarios that can be used to render UI elements */ - public Optional> getScreenshots(); - - /** The type of output returned for any intent specified during resolution. May express a particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel that will receive a specified type (e.g. "channel"). */ - public Optional getResultType(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ContextMetadata.java b/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ContextMetadata.java deleted file mode 100644 index 9ddc2f4f..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ContextMetadata.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.metadata; - -import com.finos.fdc3.api.types.AppIdentifier; - -/** - * Metadata relating to a context or intent and context received through the - * `addContextListener` and `addIntentListener` functions. - * - * @experimental Introduced in FDC3 2.0 and may be refined by further changes outside the normal FDC3 versioning policy. - */ -public interface ContextMetadata { - /** Identifier for the app instance that sent the context and/or intent. - * - * @experimental - */ - public AppIdentifier getSource(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/DisplayMetadata.java b/fdc3api/src/main/java/com/finos/fdc3/api/metadata/DisplayMetadata.java deleted file mode 100644 index d40aa886..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/DisplayMetadata.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.metadata; - -import java.util.Optional; - -/** - * A system channel will be global enough to have a presence across many apps. This gives us some hints - * to render them in a standard way. It is assumed it may have other properties too, but if it has these, - * this is their meaning. - */ -public interface DisplayMetadata { - /** - * A user-readable name for this channel, e.g: `"Red"` - */ - public Optional getName(); - - /** - * The color that should be associated within this channel when displaying this channel in a UI, e.g: `0xFF0000`. - */ - public Optional getColor(); - - /** - * A URL of an image that can be used to display this channel - */ - public Optional getGlyph(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/Icon.java b/fdc3api/src/main/java/com/finos/fdc3/api/metadata/Icon.java deleted file mode 100644 index 5ad8fbc8..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/Icon.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.metadata; - -import java.util.Optional; - -public interface Icon { - /** The icon url */ - public String getSrc(); - - /** The icon dimension, formatted as `x`. */ - public Optional getSize(); - - /** Icon media type. If not present the Desktop Agent may use the src file extension. */ - public Optional getType(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ImplementationMetadata.java b/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ImplementationMetadata.java deleted file mode 100644 index e3490407..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/metadata/ImplementationMetadata.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.metadata; - -import java.util.Optional; - -/** - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -public interface ImplementationMetadata { - /** The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - public String getfdc3Version(); - - /** The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, OpenFin etc.). */ - public String getProvider(); - - /** The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). */ - public Optional getProviderVersion(); - - /** Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - public interface optionalFeatures { - /** Used to indicate whether the exposure of 'origninating app metadata' for - * context and intent messages is supported by the Desktop Agent.*/ - public boolean OriginatingAppMetadata(); - - /** Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent.*/ - public boolean UserChannelMembershipAPIs(); - } - - /** The calling application instance's own metadata, according to the Desktop Agent (MUST include at least the `appId` and `instanceId`). */ - public AppMetadata getAppMetaData(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/types/AppIdentifier.java b/fdc3api/src/main/java/com/finos/fdc3/api/types/AppIdentifier.java deleted file mode 100644 index 16a30bf0..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/types/AppIdentifier.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.types; - -import java.util.Optional; - -/** - * Identifies an application, or instance of an application, and is used to target FDC3 API calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific instance of the application that may be addressed using that Id. - */ -public interface AppIdentifier { - /** The unique application identifier located within a specific application directory instance. An example of an appId might be 'app@sub.root' */ - public String getAppId(); - - /** An optional instance identifier, indicating that this object represents a specific instance of the application described.*/ - public Optional getInstanceId(); -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/types/IntentHandler.java b/fdc3api/src/main/java/com/finos/fdc3/api/types/IntentHandler.java deleted file mode 100644 index 579e7b58..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/types/IntentHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.types; - -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.ContextMetadata; - -/** - * Describes a callback that handles a context event and may return a promise of a Context or Channel object to be returned to the - * application that raised the intent. Used when attaching listeners for raised intents. - */ -@FunctionalInterface -public interface IntentHandler { - - /** - * Handles an intent - * - * @param context the context event - * @param contextMetadata optional metadata - * @return {@link Optional#empty()} if not result is required, or a {@link CompletionStage} that will be used to publish the - * intent result - */ - Optional> handleIntent(Context context, ContextMetadata contextMetadata); - -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/utils/JacksonUtilities.java b/fdc3api/src/main/java/com/finos/fdc3/api/utils/JacksonUtilities.java deleted file mode 100644 index 368caa9b..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/utils/JacksonUtilities.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.utils; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.List; - -public class JacksonUtilities -{ -private static final ObjectMapper jacksonObjectMapper = new ObjectMapper(); -private JacksonUtilities() { -} - -public static String serializeToString(Object obj) throws Exception { - if (obj == null) { - throw new Exception("null obj specified"); - } else { - try { - return getObjectMapper().writeValueAsString(obj); - } catch (Throwable var2) { - throw new Exception(String.format("error serializaing obj, details: %s - %s", var2.getMessage(), var2.getCause()), var2); - } - } -} - -public static String serializeToPrettyString(Object obj) throws Exception { - if (obj == null) { - throw new Exception("null obj specified"); - } else { - try { - return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(obj); - } catch (Throwable var2) { - throw new Exception(String.format("error serializaing (pretty) obj, details: %s - %s", var2.getMessage(), var2.getCause()), var2); - } - } -} - -public static T deserializeFromString(String str, Class cl) throws Exception { - if (str == null) { - throw new Exception("null str specified"); - } else if (cl == null) { - throw new Exception("null cl specified"); - } else { - try { - return getObjectMapper().readValue(str, cl); - } catch (Throwable var3) { - throw new Exception(String.format("error deserializing str '%s' for class: %s, details: %s - %s", str, cl.getName(), var3.getMessage(), var3.getCause()), var3); - } - } -} - -public static List deserializeListFromString(String message, Class cl) throws Exception { - if (message == null) { - throw new Exception("null message specified"); - } else if (cl == null) { - throw new Exception("null cl specified"); - } else { - try { - return (List)getObjectMapper().readValue(message, getObjectMapper().getTypeFactory().constructCollectionType(List.class, cl)); - } catch (Throwable var3) { - throw new Exception(String.format("error deserializing list for class: %s from message: %s, details: %s - %s", cl.getName(), message, var3.getMessage(), var3.getCause()), var3); - } - } -} - -public static ObjectMapper getObjectMapper() { - return jacksonObjectMapper; -} - - -} diff --git a/fdc3api/src/main/java/com/finos/fdc3/api/utils/StringUtilities.java b/fdc3api/src/main/java/com/finos/fdc3/api/utils/StringUtilities.java deleted file mode 100644 index 77af1ed7..00000000 --- a/fdc3api/src/main/java/com/finos/fdc3/api/utils/StringUtilities.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.api.utils; - -public class StringUtilities -{ -public static String valueAsString(Object object) { - if (object == null) { - return null; - } else { - try { - return JacksonUtilities.getObjectMapper().writeValueAsString(object); - } catch (Throwable t) { - return "N/A"; - } - } -} -} diff --git a/fdc3container/fdc3-platform.json b/fdc3container/fdc3-platform.json deleted file mode 100644 index 3b239bf8..00000000 --- a/fdc3container/fdc3-platform.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "licenseKey": "47799529-858f-429c-8b12-e106f441f985", - "runtime": { - "arguments": "--security-realm=fdc3-poc --enable-mesh", - "version": "22.94.66.4" - }, - "platform": { - "uuid": "fdc3-platform", - "defaultWindowOptions": { - "fdc3InteropApi": "1.2" - }, - "defaultViewOptions": { - "fdc3InteropApi": "1.2" - } - }, - "shortcut": { - "name": "FDC3 Demo", - "company": "WMC", - "description": "Demo of FDC3 Java API Functionality for Hackathon team WellConnect", - "icon": "https://fdc3.finos.org/img/favicon/favicon.ico", - "target": ["desktop"] - }, - "snapshot": { - "windows": [ - { - "defaultWidth": 800, - "defaultHeight": 600, - "defaultTop": 440, - "defaultLeft": 0, - "layout": { - "content": [ - { - "type": "component", - "componentName": "view", - "componentState": { - "name": "FDC3 Workbench", - "url": "https://fdc3.finos.org/toolbox/fdc3-workbench/" - } - } - ] - } - }, - { - "defaultWidth": 1120, - "defaultHeight": 600, - "defaultTop": 440, - "defaultLeft": 800, - "layout": { - "content": [ - { - "type": "component", - "componentName": "view", - "componentState": { - "name": "Receiver", - "url": "http://localhost:3000/" - } - } - ] - } - },{ - "defaultWidth": 1120, - "defaultHeight": 600, - "defaultTop": 440, - "defaultLeft": 800, - "layout": { - "content": [ - { - "type": "component", - "componentName": "view", - "componentState": { - "name": "Receiver HTML Version", - "url": "http://localhost:8080/receiver.html" - } - } - ] - } - } - ] - } -} diff --git a/fdc3container/package.json b/fdc3container/package.json deleted file mode 100644 index 28d72062..00000000 --- a/fdc3container/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "fdc3-demo", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "dev:server": "node server.js", - "dev:sender": "openfin -l -c sender.json", - "dev:receiver": "openfin -l -c receiver.json", - "dev:platform": "openfin -l -c fdc3-platform.json", - "start": "run-p dev:server dev:platform" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/finos-labs/fdc3-java-api/fdc3container" - }, - "author": "", - "license": "Apache-2.0", - "bugs": { - "url": "+https://github.com/finos-labs/fdc3-java-api/fdc3container" - }, - "homepage": "+https://github.com/finos-labs/fdc3-java-api#readme", - "dependencies": { - "express": "^4.17.1", - "npm-run-all": "^4.1.5", - "openfin-cli": "^3.0.2" - } -} diff --git a/fdc3container/receiver.html b/fdc3container/receiver.html deleted file mode 100644 index df303e90..00000000 --- a/fdc3container/receiver.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - FDC3 Instrument Receiver - - - - -

Instrument:

- - - - - - - - - - - - - - - - - - -
AttributeValue
Ticker
Name
- - - diff --git a/fdc3container/receiver.json b/fdc3container/receiver.json deleted file mode 100644 index 1db16ef8..00000000 --- a/fdc3container/receiver.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "devtools_port": 9090, - "runtime": { - "arguments": "--security-realm=platform_receiver --enable-mesh", - "version": "19.89.61.6" - }, - "platform": { - "uuid": "fdc3-demo-platform", - "autoShow": false, - "defaultWindowOptions": { - "fdc3InteropApi": "1.2", - "contextMenu": true - }, - "defaultViewOptions": { - "fdc3InteropApi": "1.2", - "contextMenu": true - } - }, - "snapshot": { - "windows": [{ - "layout": { - "content": [{ - "type": "row", - "content": [ - { - "type": "component", - "componentName": "view", - "componentState": { - "name": "Receiver", - "url": "http://localhost:8080/receiver.html" - } - } - ] - }] - } - }] - } -} \ No newline at end of file diff --git a/fdc3container/receiver/receiver.js b/fdc3container/receiver/receiver.js deleted file mode 100644 index 09db551f..00000000 --- a/fdc3container/receiver/receiver.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const initFdc3 = async () => { - // For simplicity, force channel to 'green' system channel by default. Container - // can provide facility to allow user to change this - await fdc3.joinChannel('green'); - fdc3.addContextListener('fdc3.instrument', handleContext); - try { - fdc3.addIntentListener('ViewInstrument', handleContext); - } catch (e) { - console.warn('addIntentListener is not supported'); - } - document.getElementById('statusText').innerHTML = 'Receiver Ready'; -} - -(async () => { - if (window.fdc3) { - await initFdc3(); - } else { - window.addEventListener('fdc3Ready', async () => initFdc3()); - } -})(); - -const handleContext = (context) => { - console.log(context); - let instrumentName = document.getElementById("instrument-name"); - instrumentName.innerText = context.name; - document.getElementById("ticker-id").innerText = context.id.ticker; - document.getElementById("ric-id").innerText = context.name; -} \ No newline at end of file diff --git a/fdc3container/receiver/style.css b/fdc3container/receiver/style.css deleted file mode 100644 index dae0f930..00000000 --- a/fdc3container/receiver/style.css +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -body { - background-color: #ffffff; - font-family: 'Courier New', Courier, monospace; -} - -table { - font-family: arial, sans-serif; - border-collapse: collapse; - width: 50%; -} - -td, th { - border: 1px solid #dddddd; - text-align: left; - padding: 8px; -} - -.td-attrib { - font-weight: bold; - color: gray; -} - -tr:nth-child(even) { - background-color: #dddddd; -} - -.instrument-name { - font-weight: 600; - margin-left: 5px; - text-decoration: underline; -} - -#ticker-id { - font-weight: 900; - color: rebeccapurple; -} - -#ric-id { - font-weight: 900; - color: blue; -} - -#isin-id { - font-weight: 900; - color: green; -} \ No newline at end of file diff --git a/fdc3container/sender.html b/fdc3container/sender.html deleted file mode 100644 index 47d2ab6e..00000000 --- a/fdc3container/sender.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - FDC3 Sender - - - -
Sender
- - - - - \ No newline at end of file diff --git a/fdc3container/sender.json b/fdc3container/sender.json deleted file mode 100644 index fe265d1c..00000000 --- a/fdc3container/sender.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "devtools_port": 9090, - "runtime": { - "arguments": "--security-realm=platform_sender --enable-mesh", - "version": "19.89.61.6" - }, - "platform": { - "uuid": "fdc3-demo-platform", - "autoShow": false, - "defaultWindowOptions": { - "fdc3InteropApi": "1.2", - "contextMenu": true - }, - "defaultViewOptions": { - "fdc3InteropApi": "1.2", - "contextMenu": true - } - }, - "snapshot": { - "windows": [{ - "layout": { - "content": [{ - "type": "component", - "componentName": "view", - "componentState": { - "name": "sender", - "url": "http://localhost:8080/sender.html" - } - }] - } - }] - } -} \ No newline at end of file diff --git a/fdc3container/server.js b/fdc3container/server.js deleted file mode 100644 index f17767a2..00000000 --- a/fdc3container/server.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var express = require('express'); - -var app = express(); -app.use(express.static('.')); - -app.listen(8080, () => console.log('Listening on port 8080')); \ No newline at end of file diff --git a/fdcreceiver-react-trade-app/package-lock.json b/fdcreceiver-react-trade-app/package-lock.json deleted file mode 100644 index 0f9f9f0f..00000000 --- a/fdcreceiver-react-trade-app/package-lock.json +++ /dev/null @@ -1,14235 +0,0 @@ -{ - "name": "react-search", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==" - }, - "@babel/core": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, - "@babel/generator": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "requires": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz", - "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz", - "integrity": "sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", - "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", - "requires": { - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "requires": { - "@babel/types": "^7.21.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "requires": { - "@babel/types": "^7.20.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==" - }, - "@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", - "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - } - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", - "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-decorators": "^7.8.3" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", - "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz", - "integrity": "sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz", - "integrity": "sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", - "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", - "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", - "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", - "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-flow": "^7.8.3" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", - "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", - "requires": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", - "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", - "requires": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.21.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", - "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.21.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz", - "integrity": "sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz", - "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.21.0" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx-self": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.21.0.tgz", - "integrity": "sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-transform-react-jsx-source": { - "version": "7.19.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", - "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", - "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", - "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "resolve": "^1.8.1", - "semver": "^5.5.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.21.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz", - "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/preset-env": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-env/-/preset-env-7.21.4.tgz", - "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==", - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7", - "@babel/plugin-proposal-async-generator-functions": "^7.20.7", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.21.0", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.21.0", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.20.7", - "@babel/plugin-transform-async-to-generator": "^7.20.7", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.21.0", - "@babel/plugin-transform-classes": "^7.21.0", - "@babel/plugin-transform-computed-properties": "^7.20.7", - "@babel/plugin-transform-destructuring": "^7.21.3", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.21.0", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.20.11", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-modules-systemjs": "^7.20.11", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.21.3", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.20.5", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.20.7", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.21.4", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - } - }, - "@babel/preset-typescript": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", - "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-transform-typescript": "^7.9.0" - } - }, - "@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "requires": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.21.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@csstools/convert-colors": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", - "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" - }, - "@csstools/normalize.css": { - "version": "10.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", - "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" - }, - "@emotion/babel-plugin": { - "version": "11.10.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz", - "integrity": "sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.1.4" - }, - "dependencies": { - "babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "requires": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - } - }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "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" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, - "@emotion/cache": { - "version": "11.10.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/cache/-/cache-11.10.8.tgz", - "integrity": "sha512-5fyqGHi51LU95o7qQ/vD1jyvC4uCY5GcBT+UgP4LHdpO9jPDlXqhrRr9/wCKmfoAvh5G/F7aOh4MwQa+8uEqhA==", - "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.4" - } - }, - "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "@emotion/react": { - "version": "11.10.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/react/-/react-11.10.8.tgz", - "integrity": "sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w==", - "requires": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.8", - "@emotion/cache": "^11.10.8", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "hoist-non-react-statics": "^3.3.1" - } - }, - "@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" - }, - "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==" - }, - "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" - }, - "@finos/fdc3": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@finos/fdc3/-/fdc3-2.0.1.tgz", - "integrity": "sha512-BdfTPFQKYjwTaPNHavhwmA/be4+zg/4265DAx0DoasCjnlhvLA8WB9IIJZheXTYtevE3KvGNsFTo52yYzVF3Jg==" - }, - "@floating-ui/core": { - "version": "1.2.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@floating-ui/core/-/core-1.2.6.tgz", - "integrity": "sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==" - }, - "@floating-ui/dom": { - "version": "1.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@floating-ui/dom/-/dom-1.2.7.tgz", - "integrity": "sha512-DyqylONj1ZaBnzj+uBnVfzdjjCkFCL2aA9ESHLyUOGSqb03RpbLMImP1ekIQXYs4KLk9jAjJfZAU8hXfWSahEg==", - "requires": { - "@floating-ui/core": "^1.2.6" - } - }, - "@hapi/address": { - "version": "2.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@hapi/address/-/address-2.1.4.tgz", - "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@hapi/bourne/-/bourne-1.3.2.tgz", - "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" - }, - "@hapi/hoek": { - "version": "8.5.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@hapi/hoek/-/hoek-8.5.1.tgz", - "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@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" - } - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@hapi/topo/-/topo-3.1.6.tgz", - "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", - "requires": { - "@hapi/hoek": "^8.3.0" - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "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" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" - } - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "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" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - } - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "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" - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - } - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" - }, - "@sheerun/mutationobserver-shim": { - "version": "0.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", - "integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw==" - }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", - "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==" - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", - "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==" - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", - "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==" - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", - "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==" - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "4.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz", - "integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w==" - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", - "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==" - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", - "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==" - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", - "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==" - }, - "@svgr/babel-preset": { - "version": "4.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/babel-preset/-/babel-preset-4.3.3.tgz", - "integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==", - "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", - "@svgr/babel-plugin-svg-dynamic-title": "^4.3.3", - "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", - "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", - "@svgr/babel-plugin-transform-svg-component": "^4.2.0" - } - }, - "@svgr/core": { - "version": "4.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/core/-/core-4.3.3.tgz", - "integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==", - "requires": { - "@svgr/plugin-jsx": "^4.3.3", - "camelcase": "^5.3.1", - "cosmiconfig": "^5.2.1" - } - }, - "@svgr/hast-util-to-babel-ast": { - "version": "4.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", - "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@svgr/plugin-jsx": { - "version": "4.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz", - "integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==", - "requires": { - "@babel/core": "^7.4.5", - "@svgr/babel-preset": "^4.3.3", - "@svgr/hast-util-to-babel-ast": "^4.3.2", - "svg-parser": "^2.0.0" - } - }, - "@svgr/plugin-svgo": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", - "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", - "requires": { - "cosmiconfig": "^5.2.1", - "merge-deep": "^3.0.2", - "svgo": "^1.2.2" - } - }, - "@svgr/webpack": { - "version": "4.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@svgr/webpack/-/webpack-4.3.3.tgz", - "integrity": "sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==", - "requires": { - "@babel/core": "^7.4.5", - "@babel/plugin-transform-react-constant-elements": "^7.0.0", - "@babel/preset-env": "^7.4.5", - "@babel/preset-react": "^7.0.0", - "@svgr/core": "^4.3.3", - "@svgr/plugin-jsx": "^4.3.3", - "@svgr/plugin-svgo": "^4.3.1", - "loader-utils": "^1.2.3" - } - }, - "@testing-library/dom": { - "version": "6.16.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@testing-library/dom/-/dom-6.16.0.tgz", - "integrity": "sha512-lBD88ssxqEfz0wFL6MeUyyWZfV/2cjEZZV3YRpb2IoJRej/4f1jB0TzqIOznTpfR1r34CNesrubxwIlAQ8zgPA==", - "requires": { - "@babel/runtime": "^7.8.4", - "@sheerun/mutationobserver-shim": "^0.3.2", - "@types/testing-library__dom": "^6.12.1", - "aria-query": "^4.0.2", - "dom-accessibility-api": "^0.3.0", - "pretty-format": "^25.1.0", - "wait-for-expect": "^3.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "25.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "@types/yargs": { - "version": "15.0.15", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "25.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "requires": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@testing-library/jest-dom": { - "version": "4.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@testing-library/jest-dom/-/jest-dom-4.2.4.tgz", - "integrity": "sha512-j31Bn0rQo12fhCWOUWy9fl7wtqkp7In/YP2p5ZFyRuiiB9Qs3g+hS4gAmDWONbAHcRmVooNJ5eOHQDCOmUFXHg==", - "requires": { - "@babel/runtime": "^7.5.1", - "chalk": "^2.4.1", - "css": "^2.2.3", - "css.escape": "^1.5.1", - "jest-diff": "^24.0.0", - "jest-matcher-utils": "^24.0.0", - "lodash": "^4.17.11", - "pretty-format": "^24.0.0", - "redent": "^3.0.0" - } - }, - "@testing-library/react": { - "version": "9.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@testing-library/react/-/react-9.5.0.tgz", - "integrity": "sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg==", - "requires": { - "@babel/runtime": "^7.8.4", - "@testing-library/dom": "^6.15.0", - "@types/testing-library__react": "^9.1.2" - } - }, - "@testing-library/user-event": { - "version": "7.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@testing-library/user-event/-/user-event-7.2.1.tgz", - "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" - }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", - "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" - }, - "@types/glob": { - "version": "7.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" - }, - "@types/node": { - "version": "18.16.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/node/-/node-18.16.1.tgz", - "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/q": { - "version": "1.5.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" - }, - "@types/react": { - "version": "18.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/react/-/react-18.2.0.tgz", - "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/react-dom/-/react-dom-18.2.1.tgz", - "integrity": "sha512-8QZEV9+Kwy7tXFmjJrp3XUKQSs9LTnE0KnoUb0YCguWBiNW0Yfb2iBMYZ08WPg35IR6P3Z0s00B15SwZnO26+w==", - "requires": { - "@types/react": "*" - } - }, - "@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" - }, - "@types/testing-library__dom": { - "version": "6.14.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz", - "integrity": "sha512-sMl7OSv0AvMOqn1UJ6j1unPMIHRXen0Ita1ujnMX912rrOcawe4f7wu0Zt9GIQhBhJvH2BaibqFgQ3lP+Pj2hA==", - "requires": { - "pretty-format": "^24.3.0" - } - }, - "@types/testing-library__react": { - "version": "9.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/testing-library__react/-/testing-library__react-9.1.3.tgz", - "integrity": "sha512-iCdNPKU3IsYwRK9JieSYAiX0+aYDXOGAmrC/3/M7AqqSDKnWWVv07X+Zk1uFSL7cMTUYzv4lQRfohucEocn5/w==", - "requires": { - "@types/react-dom": "*", - "@types/testing-library__dom": "*", - "pretty-format": "^25.1.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "@types/yargs": { - "version": "15.0.15", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "pretty-format": { - "version": "25.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "requires": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@types/yargs": { - "version": "13.0.12", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/yargs/-/yargs-13.0.12.tgz", - "integrity": "sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.34.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", - "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", - "requires": { - "@typescript-eslint/experimental-utils": "2.34.0", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.34.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", - "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "2.34.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@typescript-eslint/parser/-/parser-2.34.0.tgz", - "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.34.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", - "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "@webassemblyjs/ast": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/ast/-/ast-1.8.5.tgz", - "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", - "requires": { - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", - "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", - "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", - "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", - "requires": { - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", - "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" - }, - "@webassemblyjs/helper-module-context": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", - "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", - "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", - "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", - "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", - "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", - "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/helper-wasm-section": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-opt": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "@webassemblyjs/wast-printer": "1.8.5" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", - "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", - "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", - "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", - "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/floating-point-hex-parser": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-code-frame": "1.8.5", - "@webassemblyjs/helper-fsm": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", - "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "abab": { - "version": "2.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - } - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" - }, - "address": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/address/-/address-1.1.2.tgz", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" - }, - "adjust-sourcemap-loader": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz", - "integrity": "sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA==", - "requires": { - "assert": "1.4.1", - "camelcase": "5.0.0", - "loader-utils": "1.2.3", - "object-path": "0.11.4", - "regex-parser": "2.2.10" - }, - "dependencies": { - "camelcase": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==" - }, - "json5": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - } - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==" - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - } - } - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha512-JoAxEa1DfP9m2xfB/y2r/aKcwXNlltr4+0QSBC4TrLfcxyvepX2Pv0t/xpgGV5bGsDzCYV8SzjWgyCW0T9yYbA==" - }, - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "arity-n": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/arity-n/-/arity-n-1.0.4.tgz", - "integrity": "sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ==" - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==" - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.reduce": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", - "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==" - }, - "asap": { - "version": "2.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/assert/-/assert-1.4.1.tgz", - "integrity": "sha512-N+aAxov+CKVS3JuhDIQFr24XvZvwE96Wlhk9dytTg/GmwWoghdOvR8dspx8MVz71O+Y0pA3UPqHF68D6iy8UvQ==", - "requires": { - "util": "0.10.3" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" - }, - "async": { - "version": "2.6.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "autoprefixer": { - "version": "9.8.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - } - } - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" - }, - "aws4": { - "version": "1.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" - }, - "axios": { - "version": "1.3.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/axios/-/axios-1.3.6.tgz", - "integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "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" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" - } - } - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - } - }, - "babel-extract-comments": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", - "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", - "requires": { - "babylon": "^6.18.0" - } - }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "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" - } - }, - "babel-loader": { - "version": "8.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-loader/-/babel-loader-8.1.0.tgz", - "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", - "requires": { - "find-cache-dir": "^2.1.0", - "loader-utils": "^1.4.0", - "mkdirp": "^0.5.3", - "pify": "^4.0.1", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - } - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", - "requires": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "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" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - } - } - }, - "babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==" - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha512-C4Aq+GaAj83pRQ0EFgTvw5YO6T3Qz2KGrNRwIj9mSoNHVvdZY4KO2uA6HNtNXCw993iSZnckY1aLW8nOi8i4+w==" - }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha512-ocgA9VJvyxwt+qJB0ncxV8kb/CjfTcECUY4tQ5VT7nP6Aohzobm8CDFaQ5FHdvZQzLmf0sgDxB8iRXZXxwZcyA==", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "babel-preset-react-app": { - "version": "9.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", - "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", - "requires": { - "@babel/core": "7.9.0", - "@babel/plugin-proposal-class-properties": "7.8.3", - "@babel/plugin-proposal-decorators": "7.8.3", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", - "@babel/plugin-proposal-numeric-separator": "7.8.3", - "@babel/plugin-proposal-optional-chaining": "7.9.0", - "@babel/plugin-transform-flow-strip-types": "7.9.0", - "@babel/plugin-transform-react-display-name": "7.8.3", - "@babel/plugin-transform-runtime": "7.9.0", - "@babel/preset-env": "7.9.0", - "@babel/preset-react": "7.9.1", - "@babel/preset-typescript": "7.9.0", - "@babel/runtime": "7.9.0", - "babel-plugin-macros": "2.8.0", - "babel-plugin-transform-react-remove-prop-types": "0.4.24" - }, - "dependencies": { - "@babel/plugin-proposal-class-properties": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", - "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", - "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", - "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", - "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/preset-env": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-env/-/preset-env-7.9.0.tgz", - "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", - "requires": { - "@babel/compat-data": "^7.9.0", - "@babel/helper-compilation-targets": "^7.8.7", - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-proposal-async-generator-functions": "^7.8.3", - "@babel/plugin-proposal-dynamic-import": "^7.8.3", - "@babel/plugin-proposal-json-strings": "^7.8.3", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-proposal-numeric-separator": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.9.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", - "@babel/plugin-proposal-optional-chaining": "^7.9.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.8.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.8.3", - "@babel/plugin-transform-async-to-generator": "^7.8.3", - "@babel/plugin-transform-block-scoped-functions": "^7.8.3", - "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.9.0", - "@babel/plugin-transform-computed-properties": "^7.8.3", - "@babel/plugin-transform-destructuring": "^7.8.3", - "@babel/plugin-transform-dotall-regex": "^7.8.3", - "@babel/plugin-transform-duplicate-keys": "^7.8.3", - "@babel/plugin-transform-exponentiation-operator": "^7.8.3", - "@babel/plugin-transform-for-of": "^7.9.0", - "@babel/plugin-transform-function-name": "^7.8.3", - "@babel/plugin-transform-literals": "^7.8.3", - "@babel/plugin-transform-member-expression-literals": "^7.8.3", - "@babel/plugin-transform-modules-amd": "^7.9.0", - "@babel/plugin-transform-modules-commonjs": "^7.9.0", - "@babel/plugin-transform-modules-systemjs": "^7.9.0", - "@babel/plugin-transform-modules-umd": "^7.9.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", - "@babel/plugin-transform-new-target": "^7.8.3", - "@babel/plugin-transform-object-super": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.8.7", - "@babel/plugin-transform-property-literals": "^7.8.3", - "@babel/plugin-transform-regenerator": "^7.8.7", - "@babel/plugin-transform-reserved-words": "^7.8.3", - "@babel/plugin-transform-shorthand-properties": "^7.8.3", - "@babel/plugin-transform-spread": "^7.8.3", - "@babel/plugin-transform-sticky-regex": "^7.8.3", - "@babel/plugin-transform-template-literals": "^7.8.3", - "@babel/plugin-transform-typeof-symbol": "^7.8.4", - "@babel/plugin-transform-unicode-regex": "^7.8.3", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.9.0", - "browserslist": "^4.9.1", - "core-js-compat": "^3.6.2", - "invariant": "^2.2.2", - "levenary": "^1.1.1", - "semver": "^5.5.0" - } - }, - "@babel/preset-react": { - "version": "7.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/preset-react/-/preset-react-7.9.1.tgz", - "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-transform-react-display-name": "^7.8.3", - "@babel/plugin-transform-react-jsx": "^7.9.1", - "@babel/plugin-transform-react-jsx-development": "^7.9.0", - "@babel/plugin-transform-react-jsx-self": "^7.9.0", - "@babel/plugin-transform-react-jsx-source": "^7.9.0" - } - }, - "@babel/runtime": { - "version": "7.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/runtime/-/runtime-7.9.0.tgz", - "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.12", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base": { - "version": "0.11.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "bn.js": { - "version": "5.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "qs": { - "version": "6.11.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "broadcast-channel": { - "version": "3.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/broadcast-channel/-/broadcast-channel-3.7.0.tgz", - "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", - "requires": { - "@babel/runtime": "^7.7.2", - "detect-node": "^2.1.0", - "js-sha3": "0.8.0", - "microseconds": "0.2.0", - "nano-time": "1.0.0", - "oblivious-set": "1.0.0", - "rimraf": "3.0.2", - "unload": "2.2.0" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==" - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - } - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" - }, - "cacache": { - "version": "13.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cacache/-/cacache-13.0.1.tgz", - "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", - "requires": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==" - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "requires": { - "rsvp": "^4.8.4" - } - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", - "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "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" - }, - "dependencies": { - "anymatch": { - "version": "3.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "chroma-js": { - "version": "2.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chroma-js/-/chroma-js-2.4.2.tgz", - "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-css": { - "version": "4.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "clone-deep": { - "version": "0.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", - "requires": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" - }, - "coa": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "requires": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "color-string": { - "version": "1.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "compose-function": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/compose-function/-/compose-function-3.0.3.tgz", - "integrity": "sha512-xzhzTJ5eC+gmIzvZq+C3kCJHsp9os6tJkrigDRZclyGtOKINbZtE8n1Tzmeh32jW+BUDPbvZpibwvJHBLGMVwg==", - "requires": { - "arity-n": "^1.0.4" - } - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "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" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" - }, - "core-js": { - "version": "3.30.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/core-js/-/core-js-3.30.1.tgz", - "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==" - }, - "core-js-compat": { - "version": "3.30.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/core-js-compat/-/core-js-compat-3.30.1.tgz", - "integrity": "sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==", - "requires": { - "browserslist": "^4.21.5" - } - }, - "core-js-pure": { - "version": "3.30.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/core-js-pure/-/core-js-pure-3.30.1.tgz", - "integrity": "sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - } - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css": { - "version": "2.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", - "requires": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" - } - }, - "css-blank-pseudo": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", - "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", - "requires": { - "postcss": "^7.0.5" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==" - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - } - }, - "css-has-pseudo": { - "version": "0.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", - "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^5.0.0-rc.4" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "css-loader": { - "version": "3.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-loader/-/css-loader-3.4.2.tgz", - "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", - "requires": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.23", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.1.1", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.0.2", - "schema-utils": "^2.6.0" - }, - "dependencies": { - "normalize-path": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - } - } - }, - "css-prefers-color-scheme": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", - "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", - "requires": { - "postcss": "^7.0.5" - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, - "cssdb": { - "version": "4.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssdb/-/cssdb-4.4.0.tgz", - "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "cssnano": { - "version": "4.1.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==" - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==" - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" - }, - "csso": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - } - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "requires": { - "cssom": "0.3.x" - } - }, - "csstype": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" - }, - "d": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "default-gateway": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/globby/-/globby-6.1.0.tgz", - "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" - } - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==" - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-accessibility-api": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-accessibility-api/-/dom-accessibility-api-0.3.0.tgz", - "integrity": "sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA==" - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "requires": { - "utila": "~0.4" - } - }, - "dom-helpers": { - "version": "5.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - } - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "electron-to-chromium": { - "version": "1.4.374", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/electron-to-chromium/-/electron-to-chromium-1.4.374.tgz", - "integrity": "sha512-dNP9tQNTrjgVlSXMqGaj0BdrCS+9pcUvy5/emB6x8kh0YwCoDZ0Z4ce1+7aod+KhybHUd5o5LgKrc5al4kVmzQ==" - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "errno": { - "version": "0.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.62", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", - "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": "^12.1.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.3", - "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" - }, - "dependencies": { - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "requires": { - "type-fest": "^0.8.1" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - } - } - }, - "eslint-config-react-app": { - "version": "5.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", - "integrity": "sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==", - "requires": { - "confusing-browser-globals": "^1.0.9" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-loader": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-loader/-/eslint-loader-3.0.3.tgz", - "integrity": "sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw==", - "requires": { - "fs-extra": "^8.1.0", - "loader-fs-cache": "^1.0.2", - "loader-utils": "^1.2.3", - "object-hash": "^2.0.1", - "schema-utils": "^2.6.1" - } - }, - "eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-flowtype": { - "version": "4.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", - "integrity": "sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ==", - "requires": { - "lodash": "^4.17.15" - } - }, - "eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", - "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "requires": { - "locate-path": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==" - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==", - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==", - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==", - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", - "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", - "requires": { - "@babel/runtime": "^7.4.5", - "aria-query": "^3.0.0", - "array-includes": "^3.0.3", - "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.2", - "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^7.0.2", - "has": "^1.0.3", - "jsx-ast-utils": "^2.2.1" - }, - "dependencies": { - "aria-query": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", - "requires": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - } - } - }, - "eslint-plugin-react": { - "version": "7.19.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", - "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", - "requires": { - "array-includes": "^3.1.1", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.2.3", - "object.entries": "^1.1.1", - "object.fromentries": "^2.0.2", - "object.values": "^1.1.1", - "prop-types": "^15.7.2", - "resolve": "^1.15.1", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.2", - "xregexp": "^4.3.0" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-plugin-react-hooks": { - "version": "1.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", - "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==" - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" - }, - "espree": { - "version": "6.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "eventsource": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eventsource/-/eventsource-1.1.2.tgz", - "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==" - }, - "execa": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "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" - } - }, - "express": { - "version": "4.18.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "qs": { - "version": "6.11.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - } - } - }, - "ext": { - "version": "1.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "requires": { - "type": "^2.7.2" - }, - "dependencies": { - "type": { - "version": "2.7.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "requires": { - "bser": "2.1.1" - } - }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" - }, - "figures": { - "version": "3.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "requires": { - "flat-cache": "^2.0.1" - } - }, - "file-loader": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/file-loader/-/file-loader-4.3.0.tgz", - "integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==", - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^2.5.0" - } - }, - "filesize": { - "version": "6.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/filesize/-/filesize-6.0.1.tgz", - "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" - }, - "flatten": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/flatten/-/flatten-1.0.3.tgz", - "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", - "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" - }, - "fork-ts-checker-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", - "requires": { - "babel-code-frame": "^6.22.0", - "chalk": "^2.4.1", - "chokidar": "^3.3.0", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "semver": "^5.6.0", - "tapable": "^1.0.0", - "worker-rpc": "^0.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "from2": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "8.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - }, - "slash": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/slash/-/slash-1.0.0.tgz", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==" - } - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "growly": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/growly/-/growly-1.3.0.tgz", - "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==" - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/gzip-size/-/gzip-size-5.1.1.tgz", - "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - } - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "harmony-reflect": { - "version": "1.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - } - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" - }, - "history": { - "version": "4.10.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==" - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==" - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "html-entities": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" - }, - "html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "requires": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - } - } - }, - "html-webpack-plugin": { - "version": "4.0.0-beta.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", - "integrity": "sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg==", - "requires": { - "html-minifier-terser": "^5.0.1", - "loader-utils": "^1.2.3", - "lodash": "^4.17.15", - "pretty-error": "^2.1.1", - "tapable": "^1.1.3", - "util.promisify": "1.0.0" - }, - "dependencies": { - "util.promisify": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - }, - "dependencies": { - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "4.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "requires": { - "postcss": "^7.0.14" - } - }, - "identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", - "requires": { - "harmony-reflect": "^1.4.6" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" - }, - "immer": { - "version": "1.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/immer/-/immer-1.10.0.tgz", - "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==" - }, - "import-cwd": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==", - "requires": { - "import-from": "^2.1.0" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-from": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==" - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - } - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ip": { - "version": "1.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "requires": { - "is-path-inside": "^2.1.0" - } - }, - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "requires": { - "path-is-inside": "^1.0.2" - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "is-root": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==" - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "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" - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "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" - } - }, - "istanbul-reports": { - "version": "2.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "requires": { - "html-escaper": "^2.0.0" - } - }, - "jest": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "jest-cli": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "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" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "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-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "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-jsdom-fourteen": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz", - "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==", - "requires": { - "@jest/environment": "^24.3.0", - "@jest/fake-timers": "^24.3.0", - "@jest/types": "^24.3.0", - "jest-mock": "^24.0.0", - "jest-util": "^24.0.0", - "jsdom": "^14.1.0" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "jsdom": { - "version": "14.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsdom/-/jsdom-14.1.0.tgz", - "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", - "requires": { - "abab": "^2.0.0", - "acorn": "^6.0.4", - "acorn-globals": "^4.3.0", - "array-equal": "^1.0.0", - "cssom": "^0.3.4", - "cssstyle": "^1.1.1", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.0", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.1.3", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.5", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.5.0", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^6.1.2", - "xml-name-validator": "^3.0.0" - } - }, - "parse5": { - "version": "5.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "ws": { - "version": "6.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "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-get-type": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "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", - "walker": "^1.0.7" - }, - "dependencies": { - "fsevents": { - "version": "1.2.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true - } - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "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", - "co": "^4.6.0", - "expect": "^24.9.0", - "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-leak-detector": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "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" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==" - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "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" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "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", - "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", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "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", - "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" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "requires": { - "@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", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "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" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - } - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "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-watch-typeahead": { - "version": "0.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz", - "integrity": "sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q==", - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.1", - "jest-regex-util": "^24.9.0", - "jest-watcher": "^24.3.0", - "slash": "^3.0.0", - "string-length": "^3.1.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "string-length": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-length/-/string-length-3.1.0.tgz", - "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^5.2.0" - } - } - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "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" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" - } - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "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", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", - "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", - "requires": { - "jsonify": "^0.0.1" - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "json3": { - "version": "3.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, - "json5": { - "version": "2.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==" - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jsx-ast-utils": { - "version": "2.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", - "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", - "requires": { - "array-includes": "^3.1.1", - "object.assign": "^4.1.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "last-call-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", - "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", - "requires": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==" - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" - }, - "leven": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/levenary/-/levenary-1.1.1.tgz", - "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", - "requires": { - "leven": "^3.1.0" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", - "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", - "requires": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-cache-dir/-/find-cache-dir-0.1.1.tgz", - "integrity": "sha512-Z9XSBoNE7xQiV6MSgPuCfyMokH2K7JdpRkOYE1+mu3d4BFJtx3GW+f6Bo4q8IX6rlf5MYbLBKW0pjl2cWdkm2A==", - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha512-c6pv3OE78mcZ92ckebVDqg0aWSoKhOTbwCV6qbCWMk546mAL9pZln0+QsN/yQ7fkucd4+yJPLrCBXNt8Ruk+Eg==", - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" - }, - "loader-utils": { - "version": "1.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "loglevel": { - "version": "1.8.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loglevel/-/loglevel-1.8.1.tgz", - "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "requires": { - "tmpl": "1.0.5" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "requires": { - "object-visit": "^1.0.0" - } - }, - "match-sorter": { - "version": "6.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/match-sorter/-/match-sorter-6.3.1.tgz", - "integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==", - "requires": { - "@babel/runtime": "^7.12.5", - "remove-accents": "0.4.2" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "memoize-one": { - "version": "6.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "merge-deep": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "requires": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "microevent.ts": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/microevent.ts/-/microevent.ts-0.1.1.tgz", - "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "microseconds": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/microseconds/-/microseconds-0.2.0.tgz", - "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "mime": { - "version": "2.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "mini-css-extract-plugin": { - "version": "0.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", - "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", - "requires": { - "loader-utils": "^1.1.0", - "normalize-url": "1.9.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "minipass": { - "version": "3.3.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "requires": { - "minipass": "^3.0.0" - } - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "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" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==" - } - } - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", - "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" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "nano-time": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/nano-time/-/nano-time-1.0.0.tgz", - "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", - "requires": { - "big-integer": "^1.6.16" - } - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, - "util": { - "version": "0.11.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "requires": { - "inherits": "2.0.3" - } - } - } - }, - "node-notifier": { - "version": "5.4.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" - }, - "normalize-url": { - "version": "1.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-url/-/normalize-url-1.9.1.tgz", - "integrity": "sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==", - "requires": { - "object-assign": "^4.0.1", - "prepend-http": "^1.0.0", - "query-string": "^4.1.0", - "sort-keys": "^1.0.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==" - }, - "nwsapi": { - "version": "2.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/nwsapi/-/nwsapi-2.2.4.tgz", - "integrity": "sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-path": { - "version": "0.11.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-path/-/object-path-0.11.4.tgz", - "integrity": "sha512-ICbQN+aw/eAASDtaC7+SJXSAruz7fvvNjxMFfS3mTdvZaaiuuw81XXYu+9CSJeUVrS3YpRhTr862YGywMQUOWg==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", - "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", - "requires": { - "array.prototype.reduce": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.21.2", - "safe-array-concat": "^1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "oblivious-set": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/oblivious-set/-/oblivious-set-1.0.0.tgz", - "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "7.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "dependencies": { - "is-wsl": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } - } - } - }, - "opn": { - "version": "5.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optimize-css-assets-webpack-plugin": { - "version": "5.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", - "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", - "requires": { - "cssnano": "^4.1.10", - "last-call-webpack-plugin": "^3.0.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "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" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha512-J/e9xiZZQNrt+958FFzJ+auItsBGq+UrQ7nE89AUP7UOTtjHnkISANXLdayhVzh538UnLMCSlf13lFfRIAKQOA==", - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha512-3Tx1T3oM1xO/Y8Gj0sWyE78EIJZ+t+aEmXUdvQgvGmSMri7aPTHoovbXEreWKkL5j21Er60XAWLTzKbAKYOujQ==" - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "requires": { - "retry": "^0.12.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - } - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "requires": { - "pify": "^3.0.0" - } - }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "requires": { - "find-up": "^3.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" - }, - "pnp-webpack-plugin": { - "version": "1.6.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", - "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", - "requires": { - "ts-pnp": "^1.1.6" - } - }, - "portfinder": { - "version": "1.0.32", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/portfinder/-/portfinder-1.0.32.tgz", - "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", - "requires": { - "async": "^2.6.4", - "debug": "^3.2.7", - "mkdirp": "^0.5.6" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - } - } - }, - "postcss-attribute-case-insensitive": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", - "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^6.0.2" - } - }, - "postcss-browser-comments": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", - "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", - "requires": { - "postcss": "^7" - } - }, - "postcss-calc": { - "version": "7.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-color-functional-notation": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", - "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-color-gray": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", - "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-color-hex-alpha": { - "version": "5.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", - "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", - "requires": { - "postcss": "^7.0.14", - "postcss-values-parser": "^2.0.1" - } - }, - "postcss-color-mod-function": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", - "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-color-rebeccapurple": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", - "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-custom-media": { - "version": "7.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", - "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", - "requires": { - "postcss": "^7.0.14" - } - }, - "postcss-custom-properties": { - "version": "8.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", - "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", - "requires": { - "postcss": "^7.0.17", - "postcss-values-parser": "^2.0.1" - } - }, - "postcss-custom-selectors": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", - "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-dir-pseudo-class": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", - "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-double-position-gradients": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", - "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", - "requires": { - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-env-function": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-env-function/-/postcss-env-function-2.0.2.tgz", - "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-flexbugs-fixes": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", - "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-focus-visible": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", - "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-focus-within": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", - "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-font-variant": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", - "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-gap-properties": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", - "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-image-set-function": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", - "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-initial": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-initial/-/postcss-initial-3.0.4.tgz", - "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-lab-function": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", - "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-load-config": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", - "requires": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - } - }, - "postcss-loader": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-loader/-/postcss-loader-3.0.0.tgz", - "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "postcss-logical": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-logical/-/postcss-logical-3.0.0.tgz", - "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-media-minmax": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", - "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", - "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "postcss-nesting": { - "version": "7.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-nesting/-/postcss-nesting-7.0.1.tgz", - "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-normalize": { - "version": "8.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize/-/postcss-normalize-8.0.1.tgz", - "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", - "requires": { - "@csstools/normalize.css": "^10.1.0", - "browserslist": "^4.6.2", - "postcss": "^7.0.17", - "postcss-browser-comments": "^3.0.0", - "sanitize.css": "^10.0.0" - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "normalize-url": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-overflow-shorthand": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", - "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-page-break": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-page-break/-/postcss-page-break-2.0.0.tgz", - "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-place": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-place/-/postcss-place-4.0.1.tgz", - "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - } - }, - "postcss-preset-env": { - "version": "6.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", - "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", - "requires": { - "autoprefixer": "^9.6.1", - "browserslist": "^4.6.4", - "caniuse-lite": "^1.0.30000981", - "css-blank-pseudo": "^0.1.4", - "css-has-pseudo": "^0.10.0", - "css-prefers-color-scheme": "^3.1.1", - "cssdb": "^4.4.0", - "postcss": "^7.0.17", - "postcss-attribute-case-insensitive": "^4.0.1", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-gray": "^5.0.0", - "postcss-color-hex-alpha": "^5.0.3", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.8", - "postcss-custom-properties": "^8.0.11", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-double-position-gradients": "^1.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" - } - }, - "postcss-pseudo-class-any-link": { - "version": "6.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", - "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-replace-overflow-wrap": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", - "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", - "requires": { - "postcss": "^7.0.2" - } - }, - "postcss-safe-parser": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", - "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-selector-matches": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", - "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "postcss-selector-not": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", - "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==" - }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" - }, - "pretty-error": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", - "requires": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, - "promise": { - "version": "8.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "requires": { - "asap": "~2.0.6" - } - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "prr": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" - }, - "psl": { - "version": "1.9.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - }, - "q": { - "version": "1.5.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" - }, - "qs": { - "version": "6.5.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==", - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "raf": { - "version": "3.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "requires": { - "performance-now": "^2.1.0" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - } - } - }, - "react": { - "version": "16.14.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-app-polyfill": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", - "integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==", - "requires": { - "core-js": "^3.5.0", - "object-assign": "^4.1.1", - "promise": "^8.0.3", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.3", - "whatwg-fetch": "^3.0.0" - } - }, - "react-dev-utils": { - "version": "10.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-dev-utils/-/react-dev-utils-10.2.1.tgz", - "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", - "requires": { - "@babel/code-frame": "7.8.3", - "address": "1.1.2", - "browserslist": "4.10.0", - "chalk": "2.4.2", - "cross-spawn": "7.0.1", - "detect-port-alt": "1.1.6", - "escape-string-regexp": "2.0.0", - "filesize": "6.0.1", - "find-up": "4.1.0", - "fork-ts-checker-webpack-plugin": "3.1.1", - "global-modules": "2.0.0", - "globby": "8.0.2", - "gzip-size": "5.1.1", - "immer": "1.10.0", - "inquirer": "7.0.4", - "is-root": "2.1.0", - "loader-utils": "1.2.3", - "open": "^7.0.2", - "pkg-up": "3.1.0", - "react-error-overlay": "^6.0.7", - "recursive-readdir": "2.2.2", - "shell-quote": "1.7.2", - "strip-ansi": "6.0.0", - "text-table": "0.2.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "browserslist": { - "version": "4.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/browserslist/-/browserslist-4.10.0.tgz", - "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", - "requires": { - "caniuse-lite": "^1.0.30001035", - "electron-to-chromium": "^1.3.378", - "node-releases": "^1.1.52", - "pkg-up": "^3.1.0" - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" - }, - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==" - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "inquirer": { - "version": "7.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inquirer/-/inquirer-7.0.4.tgz", - "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", - "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.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "json5": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "node-releases": { - "version": "1.1.77", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - } - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "react-dom": { - "version": "16.14.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - } - }, - "react-error-overlay": { - "version": "6.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-query": { - "version": "3.39.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-query/-/react-query-3.39.3.tgz", - "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", - "requires": { - "@babel/runtime": "^7.5.5", - "broadcast-channel": "^3.4.1", - "match-sorter": "^6.0.2" - } - }, - "react-router": { - "version": "5.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-router-dom": { - "version": "5.3.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-scripts": { - "version": "3.4.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-scripts/-/react-scripts-3.4.3.tgz", - "integrity": "sha512-oSnoWmii/iKdeQiwaO6map1lUaZLmG0xIUyb/HwCVFLT7gNbj8JZ9RmpvMCZ4fB98ZUMRfNmp/ft8uy/xD1RLA==", - "requires": { - "@babel/core": "7.9.0", - "@svgr/webpack": "4.3.3", - "@typescript-eslint/eslint-plugin": "^2.10.0", - "@typescript-eslint/parser": "^2.10.0", - "babel-eslint": "10.1.0", - "babel-jest": "^24.9.0", - "babel-loader": "8.1.0", - "babel-plugin-named-asset-import": "^0.3.6", - "babel-preset-react-app": "^9.1.2", - "camelcase": "^5.3.1", - "case-sensitive-paths-webpack-plugin": "2.3.0", - "css-loader": "3.4.2", - "dotenv": "8.2.0", - "dotenv-expand": "5.1.0", - "eslint": "^6.6.0", - "eslint-config-react-app": "^5.2.1", - "eslint-loader": "3.0.3", - "eslint-plugin-flowtype": "4.6.0", - "eslint-plugin-import": "2.20.1", - "eslint-plugin-jsx-a11y": "6.2.3", - "eslint-plugin-react": "7.19.0", - "eslint-plugin-react-hooks": "^1.6.1", - "file-loader": "4.3.0", - "fs-extra": "^8.1.0", - "fsevents": "2.1.2", - "html-webpack-plugin": "4.0.0-beta.11", - "identity-obj-proxy": "3.0.0", - "jest": "24.9.0", - "jest-environment-jsdom-fourteen": "1.0.1", - "jest-resolve": "24.9.0", - "jest-watch-typeahead": "0.4.2", - "mini-css-extract-plugin": "0.9.0", - "optimize-css-assets-webpack-plugin": "5.0.3", - "pnp-webpack-plugin": "1.6.4", - "postcss-flexbugs-fixes": "4.1.0", - "postcss-loader": "3.0.0", - "postcss-normalize": "8.0.1", - "postcss-preset-env": "6.7.0", - "postcss-safe-parser": "4.0.1", - "react-app-polyfill": "^1.0.6", - "react-dev-utils": "^10.2.1", - "resolve": "1.15.0", - "resolve-url-loader": "3.1.1", - "sass-loader": "8.0.2", - "semver": "6.3.0", - "style-loader": "0.23.1", - "terser-webpack-plugin": "2.3.8", - "ts-pnp": "1.1.6", - "url-loader": "2.3.0", - "webpack": "4.42.0", - "webpack-dev-server": "3.11.0", - "webpack-manifest-plugin": "2.2.0", - "workbox-webpack-plugin": "4.3.1" - } - }, - "react-select": { - "version": "5.7.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-select/-/react-select-5.7.2.tgz", - "integrity": "sha512-cTlJkQ8YjV6T/js8wW0owTzht0hHGABh29vjLscY4HfZGkv7hc3FFTmRp9NzY/Ib1uQ36GieAKEjxpHdpCFpcA==", - "requires": { - "@babel/runtime": "^7.12.0", - "@emotion/cache": "^11.4.0", - "@emotion/react": "^11.8.1", - "@floating-ui/dom": "^1.0.1", - "@types/react-transition-group": "^4.4.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.6.0", - "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.1.2" - } - }, - "react-transition-group": { - "version": "4.4.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "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" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "requires": { - "util.promisify": "^1.0.0" - } - }, - "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", - "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regenerator-transform": { - "version": "0.15.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regex-parser": { - "version": "2.2.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regex-parser/-/regex-parser-2.2.10.tgz", - "integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==" - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" - }, - "regexpu-core": { - "version": "5.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "requires": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - } - }, - "regjsparser": { - "version": "0.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" - }, - "remove-accents": { - "version": "0.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/remove-accents/-/remove-accents-0.4.2.tgz", - "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" - }, - "renderkid": { - "version": "2.0.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "css-select": { - "version": "4.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" - }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "resolve": { - "version": "1.15.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" - }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" - }, - "resolve-url-loader": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz", - "integrity": "sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ==", - "requires": { - "adjust-sourcemap-loader": "2.0.0", - "camelcase": "5.3.1", - "compose-function": "3.0.3", - "convert-source-map": "1.7.0", - "es6-iterator": "2.0.3", - "loader-utils": "1.2.3", - "postcss": "7.0.21", - "rework": "1.0.1", - "rework-visit": "1.0.0", - "source-map": "0.6.1" - }, - "dependencies": { - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==" - }, - "json5": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "postcss": { - "version": "7.0.21", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss/-/postcss-7.0.21.tgz", - "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "retry": { - "version": "0.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" - }, - "rework": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rework/-/rework-1.0.1.tgz", - "integrity": "sha512-eEjL8FdkdsxApd0yWVZgBGzfCQiT8yqSc2H1p4jpZpQdtz7ohETiDMoje5PlM8I9WgkqkreVxFUKYOiJdVWDXw==", - "requires": { - "convert-source-map": "^0.3.3", - "css": "^2.0.0" - }, - "dependencies": { - "convert-source-map": { - "version": "0.3.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/convert-source-map/-/convert-source-map-0.3.5.tgz", - "integrity": "sha512-+4nRk0k3oEpwUB7/CalD7xE2z4VmtEnnq0GO2IPTkrooTrAhEsWvuLF5iWP1dXrwluki/azwXV1ve7gtYuPldg==" - } - } - }, - "rework-visit": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rework-visit/-/rework-visit-1.0.0.tgz", - "integrity": "sha512-W6V2fix7nCLUYX1v6eGPrBOZlc03/faqzP4sUxMAJMBMOPYhfV/RyLegTufn5gJKaOITyi+gvf0LXDZ9NzkHnQ==" - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==" - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==" - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", - "requires": { - "aproba": "^1.1.1" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-array-concat": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-array-concat/-/safe-array-concat-1.0.0.tgz", - "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "requires": { - "ret": "~0.1.10" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "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" - } - }, - "sanitize.css": { - "version": "10.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sanitize.css/-/sanitize.css-10.0.0.tgz", - "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" - }, - "sass-loader": { - "version": "8.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sass-loader/-/sass-loader-8.0.2.tgz", - "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", - "requires": { - "clone-deep": "^4.0.1", - "loader-utils": "^1.2.3", - "neo-async": "^2.6.1", - "schema-utils": "^2.6.1", - "semver": "^6.3.0" - }, - "dependencies": { - "clone-deep": { - "version": "4.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "requires": { - "kind-of": "^6.0.2" - } - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "saxes": { - "version": "3.1.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", - "requires": { - "xmlchars": "^2.1.1" - } - }, - "scheduler": { - "version": "0.19.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" - }, - "selfsigned": { - "version": "1.10.14", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/selfsigned/-/selfsigned-1.10.14.tgz", - "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shallow-clone": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", - "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", - "requires": { - "is-buffer": "^1.0.2" - } - }, - "lazy-cache": { - "version": "0.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==" - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - } - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - } - }, - "sockjs": { - "version": "0.3.20", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sockjs/-/sockjs-0.3.20.tgz", - "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.4.0", - "websocket-driver": "0.6.5" - } - }, - "sockjs-client": { - "version": "1.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sockjs-client/-/sockjs-client-1.4.0.tgz", - "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" - }, - "spdx-correct": { - "version": "3.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "7.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ssri/-/ssri-7.1.1.tgz", - "integrity": "sha512-w+daCzXN89PseTL99MkA+fxJEcU3wfaE/ah0i0lnOlpG1CYLJ2ZjzEry68YBKfLs4JfoTShrTEsJkAZuNZ/stw==", - "requires": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "stack-utils": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - } - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==" - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==" - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ==", - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "dependencies": { - "is-obj": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - }, - "strip-comments": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-comments/-/strip-comments-1.0.2.tgz", - "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", - "requires": { - "babel-extract-comments": "^1.0.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==" - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "style-loader": { - "version": "0.23.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", - "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "stylis": { - "version": "4.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/stylis/-/stylis-4.1.4.tgz", - "integrity": "sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "svg-parser": { - "version": "2.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" - }, - "table": { - "version": "5.4.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "tachyons": { - "version": "4.12.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tachyons/-/tachyons-4.12.0.tgz", - "integrity": "sha512-2nA2IrYFy3raCM9fxJ2KODRGHVSZNTW3BR0YnlGsLUf1DA3pk3YfWZ/DdfbnZK6zLZS+jUenlUGJsKcA5fUiZg==" - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" - }, - "terser": { - "version": "4.8.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/terser/-/terser-4.8.1.tgz", - "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - } - }, - "terser-webpack-plugin": { - "version": "2.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", - "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", - "requires": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.3.1", - "jest-worker": "^25.4.0", - "p-limit": "^2.3.0", - "schema-utils": "^2.6.6", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.6.12", - "webpack-sources": "^1.4.3" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "jest-worker": { - "version": "25.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/jest-worker/-/jest-worker-25.5.0.tgz", - "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "throat": { - "version": "4.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/throat/-/throat-4.1.0.tgz", - "integrity": "sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA==" - }, - "through": { - "version": "2.3.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "through2": { - "version": "2.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==" - }, - "tiny-invariant": { - "version": "1.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/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://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "requires": { - "punycode": "^2.1.0" - } - }, - "ts-pnp": { - "version": "1.1.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ts-pnp/-/ts-pnp-1.1.6.tgz", - "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "requires": { - "tslib": "^1.8.1" - } - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "type": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==" - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==" - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unload": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unload/-/unload-2.2.0.tgz", - "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", - "requires": { - "@babel/runtime": "^7.6.2", - "detect-node": "^2.0.4" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" - }, - "url": { - "version": "0.11.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/url/-/url-0.11.0.tgz", - "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - } - } - }, - "url-loader": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/url-loader/-/url-loader-2.3.0.tgz", - "integrity": "sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==", - "requires": { - "loader-utils": "^1.2.3", - "mime": "^2.4.4", - "schema-utils": "^2.5.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==" - }, - "util": { - "version": "0.10.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", - "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" - } - }, - "wait-for-expect": { - "version": "3.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/wait-for-expect/-/wait-for-expect-3.0.2.tgz", - "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==" - }, - "walker": { - "version": "1.0.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "requires": { - "makeerror": "1.0.12" - } - }, - "watchpack": { - "version": "1.7.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", - "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" - } - }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "optional": true, - "requires": { - "chokidar": "^2.1.8" - }, - "dependencies": { - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "optional": true - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - } - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" - }, - "webpack": { - "version": "4.42.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack/-/webpack-4.42.0.tgz", - "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", - "requires": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/wasm-edit": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.2.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.6.0", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "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" - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "ssri": { - "version": "6.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - } - } - } - }, - "webpack-dev-middleware": { - "version": "3.7.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "3.11.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", - "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.20", - "sockjs-client": "1.4.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "ws": { - "version": "6.2.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-manifest-plugin": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", - "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", - "requires": { - "fs-extra": "^7.0.0", - "lodash": ">=3.5 <5", - "object.entries": "^1.1.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "7.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "websocket-driver": { - "version": "0.6.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/websocket-driver/-/websocket-driver-0.6.5.tgz", - "integrity": "sha512-oBx6ZM1Gs5q2jwZuSN/Qxyy/fbgomV8+vqsmipaPKB/74hjHlKuM07jNmRhn4qa2AdUwsgxrltq+gaPsHgcl0Q==", - "requires": { - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" - }, - "workbox-background-sync": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", - "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-broadcast-update": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", - "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-build": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-build/-/workbox-build-4.3.1.tgz", - "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", - "requires": { - "@babel/runtime": "^7.3.4", - "@hapi/joi": "^15.0.0", - "common-tags": "^1.8.0", - "fs-extra": "^4.0.2", - "glob": "^7.1.3", - "lodash.template": "^4.4.0", - "pretty-bytes": "^5.1.0", - "stringify-object": "^3.3.0", - "strip-comments": "^1.0.2", - "workbox-background-sync": "^4.3.1", - "workbox-broadcast-update": "^4.3.1", - "workbox-cacheable-response": "^4.3.1", - "workbox-core": "^4.3.1", - "workbox-expiration": "^4.3.1", - "workbox-google-analytics": "^4.3.1", - "workbox-navigation-preload": "^4.3.1", - "workbox-precaching": "^4.3.1", - "workbox-range-requests": "^4.3.1", - "workbox-routing": "^4.3.1", - "workbox-strategies": "^4.3.1", - "workbox-streams": "^4.3.1", - "workbox-sw": "^4.3.1", - "workbox-window": "^4.3.1" - }, - "dependencies": { - "fs-extra": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "workbox-cacheable-response": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", - "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-core": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-core/-/workbox-core-4.3.1.tgz", - "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==" - }, - "workbox-expiration": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-expiration/-/workbox-expiration-4.3.1.tgz", - "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-google-analytics": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", - "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", - "requires": { - "workbox-background-sync": "^4.3.1", - "workbox-core": "^4.3.1", - "workbox-routing": "^4.3.1", - "workbox-strategies": "^4.3.1" - } - }, - "workbox-navigation-preload": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", - "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-precaching": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-precaching/-/workbox-precaching-4.3.1.tgz", - "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-range-requests": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", - "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-routing": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-routing/-/workbox-routing-4.3.1.tgz", - "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-strategies": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-strategies/-/workbox-strategies-4.3.1.tgz", - "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-streams": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-streams/-/workbox-streams-4.3.1.tgz", - "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "workbox-sw": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-sw/-/workbox-sw-4.3.1.tgz", - "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==" - }, - "workbox-webpack-plugin": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", - "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", - "requires": { - "@babel/runtime": "^7.0.0", - "json-stable-stringify": "^1.0.1", - "workbox-build": "^4.3.1" - } - }, - "workbox-window": { - "version": "4.3.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/workbox-window/-/workbox-window-4.3.1.tgz", - "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", - "requires": { - "workbox-core": "^4.3.1" - } - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "requires": { - "errno": "~0.1.7" - } - }, - "worker-rpc": { - "version": "0.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/worker-rpc/-/worker-rpc-0.1.1.tgz", - "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", - "requires": { - "microevent.ts": "~0.1.1" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write": { - "version": "1.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "5.2.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/ws/-/ws-5.2.3.tgz", - "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "xregexp": { - "version": "4.4.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/xregexp/-/xregexp-4.4.1.tgz", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", - "requires": { - "@babel/runtime-corejs3": "^7.12.1" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "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.2" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://artifacts.wellmanage.com/artifactory/api/npm/npm-repo/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/fdcreceiver-react-trade-app/package.json b/fdcreceiver-react-trade-app/package.json deleted file mode 100644 index 55a5da05..00000000 --- a/fdcreceiver-react-trade-app/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "react-search", - "version": "0.1.0", - "private": true, - "dependencies": { - "@finos/fdc3": "^2.0.1", - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/react": "^9.3.2", - "@testing-library/user-event": "^7.1.2", - "axios": "^1.3.6", - "chroma-js": "^2.4.2", - "react": "^16.14.0", - "react-dom": "^16.14.0", - "react-query": "^3.39.3", - "react-router-dom": "^5.2.0", - "react-scripts": "3.4.3", - "react-select": "^5.7.2", - "tachyons": "^4.12.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": "react-app" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/fdcreceiver-react-trade-app/public/favicon.ico b/fdcreceiver-react-trade-app/public/favicon.ico deleted file mode 100644 index bcd5dfd6..00000000 Binary files a/fdcreceiver-react-trade-app/public/favicon.ico and /dev/null differ diff --git a/fdcreceiver-react-trade-app/public/index.html b/fdcreceiver-react-trade-app/public/index.html deleted file mode 100644 index 90545744..00000000 --- a/fdcreceiver-react-trade-app/public/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - React Search - - - -
- - - diff --git a/fdcreceiver-react-trade-app/public/logo192.png b/fdcreceiver-react-trade-app/public/logo192.png deleted file mode 100644 index fc44b0a3..00000000 Binary files a/fdcreceiver-react-trade-app/public/logo192.png and /dev/null differ diff --git a/fdcreceiver-react-trade-app/public/logo512.png b/fdcreceiver-react-trade-app/public/logo512.png deleted file mode 100644 index a4e47a65..00000000 Binary files a/fdcreceiver-react-trade-app/public/logo512.png and /dev/null differ diff --git a/fdcreceiver-react-trade-app/public/manifest.json b/fdcreceiver-react-trade-app/public/manifest.json deleted file mode 100644 index 080d6c77..00000000 --- a/fdcreceiver-react-trade-app/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/fdcreceiver-react-trade-app/public/robots.txt b/fdcreceiver-react-trade-app/public/robots.txt deleted file mode 100644 index e9e57dc4..00000000 --- a/fdcreceiver-react-trade-app/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/fdcreceiver-react-trade-app/src/App.js b/fdcreceiver-react-trade-app/src/App.js deleted file mode 100644 index 58bee547..00000000 --- a/fdcreceiver-react-trade-app/src/App.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from "react"; -import Search from "./components/Search"; - -function App() { - return ( -
- -
- ); -} - -export default App; diff --git a/fdcreceiver-react-trade-app/src/components/Card.js b/fdcreceiver-react-trade-app/src/components/Card.js deleted file mode 100644 index cd625056..00000000 --- a/fdcreceiver-react-trade-app/src/components/Card.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as fdc3 from '@finos/fdc3'; - -import React, {useState} from 'react'; - -import axios from "axios"; -import search from "./Search"; - -function Card({result}) { - - const [searchCard, setSearchCard] = useState(result); - const [cardPricing, setCardPricing] = useState({}); - const handleTrades = e => { - const sign = e.currentTarget.getAttribute('transtype') - let updatedTrade = { - ...searchCard, - trades: (sign === "buy") ? searchCard.trades + 100 : (searchCard.trades === 0) ? 0 : searchCard.trades - 100 - }; - setSearchCard(updatedTrade); - const position = { - type: 'fdc3.position', - instrument: { - type: "fdc3.instrument", - name:searchCard.name, - id: { - 'ticker': searchCard.id - } - }, - holding: updatedTrade.trades - }; - - fdc3.broadcast(position); - - } - - const findPricing = e => { - const ticker = searchCard.id; - const apikey = 'cEaEylhYZbVcKqSF_oZbOexAppYQRlmK'; - if (!!ticker && ticker !== "") { - axios.get('https://api.polygon.io/v2/aggs/ticker/' + ticker + '/prev?adjusted=true&apiKey=' + apikey).then(response => { - if (response.status === 200 && response.data.results.length>0) { - const prevClosePricing = response.data.results; - setCardPricing({...searchCard,...prevClosePricing[0]}); - } - }) - } - - } - - - return ( -
-
-

Reference

-

{searchCard.name}

-

{searchCard.id}

-

{searchCard.sector}

-

Pricing

-

Trading volume {cardPricing.v}

-

Weighted Average {cardPricing.vw}

-

Close price {cardPricing.c}

-

Open price {cardPricing.o}

-

Lowest Price {cardPricing.l}

-

Highest Price {cardPricing.h}

- -
-
- - - -
-
- ); -} - -export default Card; \ No newline at end of file diff --git a/fdcreceiver-react-trade-app/src/components/ChannelDropdown.js b/fdcreceiver-react-trade-app/src/components/ChannelDropdown.js deleted file mode 100644 index f4406615..00000000 --- a/fdcreceiver-react-trade-app/src/components/ChannelDropdown.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as fdc3 from "@finos/fdc3"; - -import React, {useEffect, useState} from "react"; - -import Select from "react-select"; -import chroma from "chroma-js"; -import {useQuery} from "react-query"; - -const dot = (color = "transparent") => ({ - alignItems: "center", - display: "flex", - - ":before": { - backgroundColor: color, - borderRadius: 10, - content: '" "', - display: "block", - marginRight: 8, - height: 10, - width: 10, - }, -}); -const colourStyles = { - control: (styles) => ({...styles, backgroundColor: "white"}), - option: (styles, {data, isDisabled, isFocused, isSelected}) => { - const color = chroma(data.color); - return { - ...styles, - backgroundColor: isDisabled - ? undefined - : isSelected - ? data.color - : isFocused - ? color.alpha(0.1).css() - : undefined, - color: isDisabled - ? "#ccc" - : isSelected - ? chroma.contrast(color, "white") > 2 - ? "white" - : "black" - : data.color, - cursor: isDisabled ? "not-allowed" : "default", - - ":active": { - ...styles[":active"], - backgroundColor: !isDisabled - ? isSelected - ? data.color - : color.alpha(0.3).css() - : undefined, - }, - }; - }, - input: (styles) => ({...styles, ...dot()}), - placeholder: (styles) => ({...styles, ...dot("#ccc")}), - singleValue: (styles, {data}) => ({...styles, ...dot(data.color)}), -}; - -async function fetchUserChannels() { - let channels = []; - if (!!window.fdc3) { - channels = await fdc3.getUserChannels(); - return channels; - } -} - -export default function ChannelDropdown(props) { - const [channel, setChannel] = useState(props.defaultChannel); - const {data, isLoading} = useQuery("data", fetchUserChannels); - - useEffect(() => { - async function joinChannel() { - await fdc3.leaveCurrentChannel(); - console.log("Leaving current channel"); - await fdc3.joinChannel(channel.value); - console.log(`Setting channel to ${channel.value}`); - } - - if (!!window.fdc3) { - joinChannel(); - } - }); - - if (isLoading) return
Loading...
; - - if (!data) return
Error while fetching data...
; - - const channels = data.map((channel) => ({ - value: channel.id, - label: channel.id, - color: channel.displayMetadata.color, - })); - - const defaultChannel = - channels.find((c) => c.id === channel.value) || channels[0]; - - return ( - - - {searchList()} - - - ); -} - -export default Search; diff --git a/fdcreceiver-react-trade-app/src/components/SearchList.js b/fdcreceiver-react-trade-app/src/components/SearchList.js deleted file mode 100644 index 808c3bb1..00000000 --- a/fdcreceiver-react-trade-app/src/components/SearchList.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Card from './Card'; -import React from 'react'; - -function SearchList({ searchResults }) { - const filtered = searchResults.map( result => ); - return ( -
- {filtered} -
- ); -} - -export default SearchList; \ No newline at end of file diff --git a/fdcreceiver-react-trade-app/src/data/initialDetails.js b/fdcreceiver-react-trade-app/src/data/initialDetails.js deleted file mode 100644 index 0afde4aa..00000000 --- a/fdcreceiver-react-trade-app/src/data/initialDetails.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import axios from "axios"; - -async function getTickers() { - const data = axios.get('https://pkgstore.datahub.io/core/s-and-p-500-companies/constituents_json/data/297344d8dc0a9d86b8d107449c851cc8/constituents_json.json') - return data -} - - -async function initialDetails() { - let tickers = await getTickers(); - let result = []; - if (!!tickers.data) { - result = tickers.data.map((tick) => { - return { - "id": tick.Symbol, - "sector": - tick.Sector, - "name": - tick.Name, - "trades":0 - } - }); - } - return result; -} - - -export default initialDetails; \ No newline at end of file diff --git a/fdcreceiver-react-trade-app/src/index.js b/fdcreceiver-react-trade-app/src/index.js deleted file mode 100644 index efc0842f..00000000 --- a/fdcreceiver-react-trade-app/src/index.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { QueryClient, QueryClientProvider } from "react-query"; - -import App from "./App"; -import React from "react"; -import ReactDOM from "react-dom"; - -ReactDOM.render( - - - - - , - document.getElementById("root") -); diff --git a/openfin-fdc3-adapter/pom.xml b/openfin-fdc3-adapter/pom.xml deleted file mode 100644 index c7672069..00000000 --- a/openfin-fdc3-adapter/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - 4.0.0 - - com.finos.fdc3.api - finos-bmo-hackathon - 1.0.0-SNAPSHOT - - - openfin-fdc3-adapter - - - 11 - 11 - UTF-8 - - - - - co.openfin - openfin-desktop-java-adapter - 11.0.1 - - - com.finos.fdc3.api - fdc3api - ${project.version} - compile - - - - \ No newline at end of file diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannel.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannel.java deleted file mode 100644 index 0cb1f246..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannel.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.adapter.openfin; - -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -import com.finos.fdc3.api.channel.Channel; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.metadata.DisplayMetadata; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.api.types.Listener; -import com.openfin.desktop.interop.ContextGroupInfo; - -/** - * OpenFin implementation of FDC3 {@link Channel} - * - * @author Tim Jenkel - */ -public class OpenFinChannel implements Channel { - - private final ContextGroupInfo info; - - private final Type type; - - private final OpenFinDesktopAgent desktopAgent; - - public OpenFinChannel(ContextGroupInfo info, Type type, OpenFinDesktopAgent desktopAgent) { - - this.info = info; - this.type = type; - this.desktopAgent = desktopAgent; - } - - @Override - public String getId() { - - return info.getId(); - } - - @Override - public Type getType() { - - return type; - } - - @Override - public Optional displayMetadata() { - - return Optional.ofNullable(info.getDisplayMetadata()).map(OpenFinChannelDisplayMetadata::new); - } - - @Override - public CompletionStage broadcast(Context context) { - - return desktopAgent.broadcastOnChannel(context, getId()); - } - - @Override - public CompletionStage> getCurrentContext() { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage> getCurrentContext(String contextType) { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage addContextListener(String contextType, ContextHandler handler) { - - throw new UnsupportedOperationException( - "Channel.addContextListener is not supported, please use DesktopAgent.addContextListener"); - } - -} diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannelDisplayMetadata.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannelDisplayMetadata.java deleted file mode 100644 index a4baa5ac..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinChannelDisplayMetadata.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.adapter.openfin; - -import java.util.Optional; - -import com.openfin.desktop.interop.DisplayMetadata; - -/** - * Adapter to convert {@link com.openfin.desktop.interop.DisplayMetadata} to - * {@link com.finos.fdc3.api.common.metadata.DisplayMetadata} - * - * @author Tim Jenkel - */ -public class OpenFinChannelDisplayMetadata implements com.finos.fdc3.api.metadata.DisplayMetadata { - - private DisplayMetadata displayMetadata; - - public OpenFinChannelDisplayMetadata(DisplayMetadata displayMetadata) { - - this.displayMetadata = displayMetadata; - } - - @Override - public Optional getName() { - - return Optional.ofNullable(displayMetadata.getName()); - } - - @Override - public Optional getColor() { - - return Optional.ofNullable(displayMetadata.getColor()); - } - - @Override - public Optional getGlyph() { - - return Optional.ofNullable(displayMetadata.getGlyph()); - } - -} diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinContextListenerAdapter.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinContextListenerAdapter.java deleted file mode 100644 index 4d2e59c4..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinContextListenerAdapter.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.adapter.openfin; - -import java.util.Objects; - -import com.finos.fdc3.api.context.Position; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.api.utils.JacksonUtilities; -import com.openfin.desktop.interop.ContextListener; - -/** - * Adapter that converts FDC3 {@link ContextHandler} to OpenFin {@link ContextListener} - * - * @author Tim Jenkel - */ -public class OpenFinContextListenerAdapter implements ContextListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenFinContextListenerAdapter.class); - - private final ContextHandler handler; - - public OpenFinContextListenerAdapter(ContextHandler handler) { - - this.handler = Objects.requireNonNull(handler); - } - - @Override - public void onContext(com.openfin.desktop.interop.Context openFinContext) { - - Context fdc3Context; - try { - // TODO deserialize to correct class based on context type - if(openFinContext.getType().equalsIgnoreCase("fdc3.position")){ - fdc3Context = JacksonUtilities.deserializeFromString(openFinContext.toString(), Position.class); - }else{ - fdc3Context = JacksonUtilities.deserializeFromString(openFinContext.toString(), Context.class); - } - - } catch (Exception e) { - LOGGER.error("Error deserializing context: {}", openFinContext, e); - return; - } - handler.handleContext(fdc3Context, null); - } - -} diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinDesktopAgent.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinDesktopAgent.java deleted file mode 100644 index 36f774c1..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinDesktopAgent.java +++ /dev/null @@ -1,314 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.adapter.openfin; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.api.DesktopAgent; -import com.finos.fdc3.api.channel.Channel; -import com.finos.fdc3.api.channel.Channel.Type; -import com.finos.fdc3.api.channel.PrivateChannel; -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.errors.FDC3ConnectionException; -import com.finos.fdc3.api.metadata.AppIntent; -import com.finos.fdc3.api.metadata.AppMetadata; -import com.finos.fdc3.api.metadata.ImplementationMetadata; -import com.finos.fdc3.api.metadata.IntentResolution; -import com.finos.fdc3.api.types.AppIdentifier; -import com.finos.fdc3.api.types.ContextHandler; -import com.finos.fdc3.api.types.IntentHandler; -import com.finos.fdc3.api.types.Listener; -import com.openfin.desktop.DesktopConnection; -import com.openfin.desktop.DesktopStateListener; -import com.openfin.desktop.interop.Intent; -import com.openfin.desktop.interop.InteropClient; - -/** - * FDC3 {@link DesktopAgent} implementation using OpenFin Java adapter - * - * @author Tim Jenkel - */ -public class OpenFinDesktopAgent implements DesktopAgent { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenFinDesktopAgent.class); - - private final OpenFinFDC3Config config; - - private DesktopConnection desktopConnection; - - private CompletableFuture interopClientFuture; - - private volatile String currentChannelId; - - public OpenFinDesktopAgent(OpenFinFDC3Config config) { - - this.config = config; - } - - protected OpenFinFDC3Config getConfig() { - - return config; - } - - protected CompletionStage getInteropClient() { - - if (interopClientFuture == null || interopClientFuture.isCompletedExceptionally()) { - interopClientFuture = new CompletableFuture().orTimeout(config.getTimeout().toMillis(), - TimeUnit.MILLISECONDS); - CompletableFuture.runAsync(this::connect); - } - return interopClientFuture; - } - - private void connect() { - - try { - if (desktopConnection == null) { - LOGGER.info("Initializing OpenFin connection"); - desktopConnection = new DesktopConnection(getConfig().getUuid()); - } - if (desktopConnection.isConnected()) { - createInteropClient(); - } else { - LOGGER.info("Connecting to OpenFin"); - desktopConnection.connect(getConfig().getRuntimeConfiguration(), new OpenFinStateListener(), - (int) getConfig().getTimeout().toSeconds()); - } - } catch (Exception e) { - String msg = "Exception connecting to OpenFin"; - LOGGER.error(msg, e); - Optional.ofNullable(interopClientFuture) - .ifPresent(future -> future.completeExceptionally(new FDC3ConnectionException(msg, e))); - } - } - - private void createInteropClient() { - - LOGGER.info("Creating interop client"); - desktopConnection.getInterop().connect(getConfig().getBrokerName()).thenAccept(client -> { - LOGGER.info("Connected interop client"); - if (interopClientFuture == null) { - interopClientFuture = CompletableFuture.completedFuture(client); - } else { - interopClientFuture.complete(client); - } - }); - } - - @Override - public CompletionStage open(AppIdentifier app, Context context) { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage findIntent(String indent, Context context, String resultType) { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage> findIntentsByContext(Context context, String resultType) { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage> findInstances(AppIdentifier app) { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage broadcast(Context context) { - - return getInteropClient().thenCompose(client -> client.setContext(convertToOpenFinContext(context))); - } - - protected CompletionStage broadcastOnChannel(Context context, String channelId) { - - return getInteropClient().thenCompose(client -> { - if (channelId.equals(currentChannelId)) { - return client.setContext(convertToOpenFinContext(context)); - } - throw new UnsupportedOperationException("Broadcasting is only supported on the currently joined channel"); - }); - } - - @Override - public CompletionStage raiseIntent(String intentName, Context context) { - - Intent intent = new Intent(); - intent.setName(intentName); - intent.setContext(convertToOpenFinContext(context)); - return getInteropClient().thenCompose(client -> client.fireIntent(intent)).thenApply(result -> { - // TODO OpenFin doesn't provide IntentResolution details - return null; - }); - } - - @Override - public CompletionStage raiseIntent(String intentName, Context context, AppIdentifier app) { - - if (app == null) { - return raiseIntent(intentName, context); - } - throw new UnsupportedOperationException("raiseIntent for a specific app is not supported"); - } - - @Override - public CompletionStage raiseIntentForContext(Context context, AppIdentifier app) { - - // TODO confirm if OpenFin handling of intent without name matches FDC3 spec for raiseIntentForContext - return raiseIntent(null, context, app); - } - - @Override - public CompletionStage addContextListener(String contextType, ContextHandler handler) { - - final OpenFinContextListenerAdapter listener = new OpenFinContextListenerAdapter(handler); - return getInteropClient().thenCompose(client -> client.addContextListener(contextType, listener)) - .thenApply(result -> (() -> getInteropClient() - .thenCompose(client -> client.removeContextListener(contextType, listener) - .thenRun(() -> LOGGER.info("Unsubscribed context handler for type {}", contextType)) - .exceptionally(ex -> { - LOGGER.error("Error unsubscribing context handler for type {}", contextType, ex); - return null; - })))); - } - - @Override - public CompletionStage addIntentListener(String intent, IntentHandler handler) { - - final OpenFinIntentListenerAdapter listener = new OpenFinIntentListenerAdapter(handler); - return getInteropClient().thenCompose(client -> client.registerIntentListener(intent, listener)) - .thenApply(result -> (() -> { - throw new UnsupportedOperationException("Removing an intent listener is not supported"); - })); - }; - - @Override - public CompletionStage joinUserChannel(String channelId) { - - return getInteropClient().thenCompose(client -> client.joinContextGroup(channelId)) - .thenRun(() -> currentChannelId = channelId); - } - - @Override - public CompletionStage> getUserChannels() { - - return getInteropClient().thenCompose(InteropClient::getContextGroups).thenApply(groups -> Stream.of(groups) - .map(group -> new OpenFinChannel(group, Type.User, this)).collect(Collectors.toList())); - } - - @Override - public CompletionStage getOrCreateChannel(String channelId) { - - // TODO this will get the channel if it exists, but will throw an error if the channel doesn't exist - // need OpenFin support to create App channels - return getInteropClient().thenCompose(client -> client.getInfoForContextGroup(channelId)) - .thenApply(group -> new OpenFinChannel(group, Type.User, this)); - } - - @Override - public CompletionStage createPrivateChannel() { - - throw new UnsupportedOperationException(); - } - - @Override - public CompletionStage> getCurrentChannel() { - - return Optional.ofNullable(currentChannelId) - .map(channelId -> getOrCreateChannel(channelId).thenApply(Optional::of)) - .orElseGet(() -> CompletableFuture.completedFuture(Optional.empty())); - } - - @Override - public CompletionStage leaveCurrentChannel() { - - return getInteropClient().thenCompose(InteropClient::removeFromContextGroup) - .thenRun(() -> currentChannelId = null); - } - - @Override - public CompletionStage getInfo() { - - // TODO Auto-generated method stub - return null; - } - - @Override - public CompletionStage getAppMetadata(AppIdentifier app) { - - throw new UnsupportedOperationException(); - } - - protected com.openfin.desktop.interop.Context convertToOpenFinContext(Context context) { - - return new com.openfin.desktop.interop.Context(new JSONObject(context)); - } - - private class OpenFinStateListener implements DesktopStateListener { - - @Override - public void onReady() { - - LOGGER.info("OpenFin connection ready"); - createInteropClient(); - } - - @Override - public void onClose(String error) { - - LOGGER.warn("OpenFin connection closed: {}", error); - } - - @Override - public void onError(String reason) { - - String msg = "Error connecting to OpenFin: " + reason; - LOGGER.error(msg); - Optional.ofNullable(interopClientFuture) - .ifPresent(future -> interopClientFuture.completeExceptionally(new FDC3ConnectionException(msg))); - } - - @Override - public void onMessage(String message) { - - LOGGER.debug("OpenFin message in: {}", message); - } - - @Override - public void onOutgoingMessage(String message) { - - LOGGER.debug("OpenFin message out: {}", message); - } - - } - -} diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinFDC3Config.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinFDC3Config.java deleted file mode 100644 index ddf528c0..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinFDC3Config.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.finos.fdc3.adapter.openfin; - -import java.time.Duration; - -import com.openfin.desktop.RuntimeConfiguration; - -/** - * Configuration for setting up an OpenFin FDC3 connection - * - * @author Tim Jenkel - */ -public class OpenFinFDC3Config { - - private RuntimeConfiguration runtimeConfiguration; - - private String uuid; - - private String brokerName; - - private Duration timeout = Duration.ofSeconds(20); - - public RuntimeConfiguration getRuntimeConfiguration() { - - return runtimeConfiguration; - } - - public void setRuntimeConfiguration(RuntimeConfiguration runtimeConfiguration) { - - this.runtimeConfiguration = runtimeConfiguration; - } - - public String getUuid() { - - return uuid; - } - - public void setUuid(String uuid) { - - this.uuid = uuid; - } - - public String getBrokerName() { - - return brokerName; - } - - public void setBrokerName(String brokerName) { - - this.brokerName = brokerName; - } - - public Duration getTimeout() { - - return timeout; - } - - public void setTimeout(Duration timeout) { - - this.timeout = timeout; - } - -} diff --git a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinIntentListenerAdapter.java b/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinIntentListenerAdapter.java deleted file mode 100644 index 5e4e884a..00000000 --- a/openfin-fdc3-adapter/src/main/java/com/finos/fdc3/adapter/openfin/OpenFinIntentListenerAdapter.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2023 Wellington Management Company LLP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - package com.finos.fdc3.adapter.openfin; - -import java.util.Optional; -import java.util.concurrent.CompletionStage; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.finos.fdc3.api.context.Context; -import com.finos.fdc3.api.types.IntentHandler; -import com.finos.fdc3.api.types.IntentResult; -import com.finos.fdc3.api.utils.JacksonUtilities; -import com.openfin.desktop.interop.Intent; -import com.openfin.desktop.interop.IntentListener; - -/** - * Adapter to convert FINOS {@link IntentHandler} to OpenFin {@link IntentListener} - * - * @author Tim Jenkel - */ -public class OpenFinIntentListenerAdapter implements IntentListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenFinIntentListenerAdapter.class); - - private final IntentHandler handler; - - public OpenFinIntentListenerAdapter(IntentHandler handler) { - - this.handler = handler; - } - - @Override - public void onIntent(Intent intent) { - - Context fdc3Context; - try { - // TODO deserialize to correct class based on context type - fdc3Context = JacksonUtilities.deserializeFromString(intent.getContext().toString(), Context.class); - } catch (Exception e) { - LOGGER.error("Error deserializing intent context: {}", intent, e); - return; - } - Optional> result = handler.handleIntent(fdc3Context, null); - if (result.isPresent()) { - LOGGER.warn("Ignoring intent result not supported by OpenFin"); - } - } - -} diff --git a/pom.xml b/pom.xml index 8f5c96d2..4d94f0ec 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.finos.fdc3.api - finos-bmo-hackathon + org.finos.fdc3 + fdc3-parent 1.0.0-SNAPSHOT pom - finos-bmo-hackathon - http://maven.apache.org + FDC3 Java API + A Java implementation of the FDC3 standard for financial desktop + interoperability, providing the Desktop Agent API, its WebSocket transport and the + generated context and protocol types. + https://github.com/finos-labs/fdc3-java-api + 2025 + + + FINOS + https://www.finos.org/ + + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + FDC3 Maintainers + FINOS + https://www.finos.org/ + https://github.com/finos-labs/fdc3-java-api/graphs/contributors + + + + + scm:git:https://github.com/finos-labs/fdc3-java-api.git + scm:git:ssh://git@github.com/finos-labs/fdc3-java-api.git + https://github.com/finos-labs/fdc3-java-api + HEAD + + + + GitHub Issues + https://github.com/finos-labs/fdc3-java-api/issues + + - fdc3api - client - openfin-fdc3-adapter + fdc3-standard + fdc3-schema + fdc3-context + fdc3-agent-proxy + fdc3-get-agent + fdc3-example-app + fdc3-java-workbench - 11 - 11 + UTF-8 + + 17 + 0.8.12 + 3.11.0 + 3.2.5 + 3.6.3 + 3.3.0 + + + 2.0.9 + 2.18.8 + 5.10.1 + 1.10.1 + 7.15.0 + 1.3.0 + 6.1.2 + 2.1.5 + 2.1.1 + 1.5.6 + + v22.14.0 + 10.9.2 + 26.0.0 + + + 3.0.0-alpha.5 + + + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + pom + import + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + + + org.junit.platform + junit-platform-suite + ${junit.platform.version} + + + + io.cucumber + cucumber-spring + ${cucumber.version} + + + io.cucumber + cucumber-junit-platform-engine + ${cucumber.version} + + + org.finos + cucumber-testing-steps + ${cucumber.testing.steps.version} + + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-test + ${spring.version} + + + + jakarta.websocket + jakarta.websocket-client-api + ${jakarta.websocket.version} + + + org.glassfish.tyrus.bundles + tyrus-standalone-client + ${tyrus.version} + + + org.glassfish.tyrus + tyrus-server + ${tyrus.version} + + + org.glassfish.tyrus + tyrus-container-grizzly-server + ${tyrus.version} + + + + com.networknt + json-schema-validator + ${networknt.version} + + + + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${maven.compiler.release} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven.javadoc.plugin.version} + + all,-missing + true + + + + + + + org.jacoco + jacoco-maven-plugin + + + prepare-agent + + prepare-agent + + + + report + test + + report + + + + **/generated/** + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + +