From adf2a13cb665a244948920ad09ca16b7e4e711c2 Mon Sep 17 00:00:00 2001 From: zowe-robot <42546701+zowe-robot@users.noreply.github.com> Date: Tue, 14 Jan 2025 03:10:02 -0500 Subject: [PATCH] chore: Update all patch dependencies (v2.x.x) (#3876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Renovate Bot Signed-off-by: Pavel Jareš Signed-off-by: nx673747 Signed-off-by: ac892247 Co-authored-by: Renovate Bot Co-authored-by: Pavel Jareš Co-authored-by: nx673747 Co-authored-by: ac892247 --- .github/workflows/integration-tests.yml | 102 +- .gitignore | 6 +- .npmrc | 2 + api-catalog-ui/frontend/.npmrc | 2 + api-catalog-ui/frontend/package-lock.json | 234 +- api-catalog-ui/frontend/package.json | 16 +- .../config/WebSecurity.java | 45 +- .../filters/RequestAttributesProvider.java | 13 +- gradle/versions.gradle | 32 +- metrics-service-ui/frontend/.npmrc | 2 + metrics-service-ui/frontend/package-lock.json | 307 ++- metrics-service-ui/frontend/package.json | 6 +- onboarding-enabler-nodejs-sample-app/.npmrc | 2 + .../build.gradle | 2 +- .../package-lock.json | 2300 +++++++++-------- .../package.json | 59 +- .../src/index.js | 8 +- onboarding-enabler-nodejs/.babelrc | 3 + onboarding-enabler-nodejs/.eslintrc | 10 + onboarding-enabler-nodejs/.npmrc | 2 + onboarding-enabler-nodejs/gulpfile.babel.js | 64 + .../license-checker-config.json | 16 + onboarding-enabler-nodejs/package.json | 38 +- onboarding-enabler-nodejs/src/AwsMetadata.js | 122 + .../src/ConfigClusterResolver.js | 87 + .../src/DnsClusterResolver.js | 164 ++ onboarding-enabler-nodejs/src/EurekaClient.js | 698 +++++ onboarding-enabler-nodejs/src/Logger.js | 81 + .../src/defaultConfig.js | 57 + onboarding-enabler-nodejs/src/deltaUtils.js | 51 + onboarding-enabler-nodejs/src/index.js | 70 +- .../test/AwsMetadata.test.js | 180 ++ .../test/ConfigClusterResolver.test.js | 220 ++ .../test/DnsClusterResolver.test.js | 358 +++ .../test/EurekaClient.test.js | 1407 ++++++++++ onboarding-enabler-nodejs/test/Logger.test.js | 123 + .../test/deltaUtil.test.js | 73 + .../test/eureka-client-test.yml | 3 + .../test/eureka-client.yml | 11 + .../test/fixtures/config.yml | 2 + .../test/fixtures/malformed-config.yml | 3 + .../test/integration.test.js | 102 + scripts/docs/.npmrc | 2 + scripts/release_components/.npmrc | 2 + scripts/release_docs/.npmrc | 2 + zowe-cli-id-federation-plugin/.npmrc | 2 + zss-sample-service/.npmrc | 2 + zss-sample-service/package.json | 2 +- 48 files changed, 5461 insertions(+), 1634 deletions(-) create mode 100644 .npmrc create mode 100644 api-catalog-ui/frontend/.npmrc create mode 100644 metrics-service-ui/frontend/.npmrc create mode 100644 onboarding-enabler-nodejs-sample-app/.npmrc create mode 100644 onboarding-enabler-nodejs/.babelrc create mode 100644 onboarding-enabler-nodejs/.eslintrc create mode 100644 onboarding-enabler-nodejs/.npmrc create mode 100644 onboarding-enabler-nodejs/gulpfile.babel.js create mode 100644 onboarding-enabler-nodejs/license-checker-config.json create mode 100644 onboarding-enabler-nodejs/src/AwsMetadata.js create mode 100644 onboarding-enabler-nodejs/src/ConfigClusterResolver.js create mode 100644 onboarding-enabler-nodejs/src/DnsClusterResolver.js create mode 100644 onboarding-enabler-nodejs/src/EurekaClient.js create mode 100644 onboarding-enabler-nodejs/src/Logger.js create mode 100644 onboarding-enabler-nodejs/src/defaultConfig.js create mode 100644 onboarding-enabler-nodejs/src/deltaUtils.js create mode 100644 onboarding-enabler-nodejs/test/AwsMetadata.test.js create mode 100644 onboarding-enabler-nodejs/test/ConfigClusterResolver.test.js create mode 100644 onboarding-enabler-nodejs/test/DnsClusterResolver.test.js create mode 100644 onboarding-enabler-nodejs/test/EurekaClient.test.js create mode 100644 onboarding-enabler-nodejs/test/Logger.test.js create mode 100644 onboarding-enabler-nodejs/test/deltaUtil.test.js create mode 100644 onboarding-enabler-nodejs/test/eureka-client-test.yml create mode 100644 onboarding-enabler-nodejs/test/eureka-client.yml create mode 100644 onboarding-enabler-nodejs/test/fixtures/config.yml create mode 100644 onboarding-enabler-nodejs/test/fixtures/malformed-config.yml create mode 100644 onboarding-enabler-nodejs/test/integration.test.js create mode 100644 scripts/docs/.npmrc create mode 100644 scripts/release_components/.npmrc create mode 100644 scripts/release_docs/.npmrc create mode 100644 zss-sample-service/.npmrc diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5cd74a599f..0b67aba092 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} - uses: ./.github/actions/setup @@ -71,7 +71,7 @@ jobs: image: ghcr.io/balhar-jakub/metrics-service:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -84,7 +84,7 @@ jobs: - uses: ./.github/actions/dump-jacoco if: always() - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITests-${{ env.JOB_ID }} @@ -118,7 +118,7 @@ jobs: image: ghcr.io/balhar-jakub/discoverable-client:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -164,7 +164,7 @@ jobs: image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -180,7 +180,7 @@ jobs: java -jar ./scripts/jacococli.jar dump --address cloud-gateway-service --port 6310 --destfile ./results/cloud-gateway-service.exec - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CloudGatewayProxy-${{ env.JOB_ID }} @@ -208,7 +208,7 @@ jobs: mock-services: image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -224,7 +224,7 @@ jobs: java -jar ./scripts/jacococli.jar dump --address cloud-gateway-service --port 6310 --destfile ./results/cloud-gateway-service.exec - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CloudGatewayServiceRouting-${{ env.JOB_ID }} @@ -288,7 +288,7 @@ jobs: ZWE_CONFIGS_APIML_SERVICE_ADDITIONALREGISTRATION_0_ROUTES_SERVICEURL: / steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -304,7 +304,7 @@ jobs: java -jar ./scripts/jacococli.jar dump --address cloud-gateway-service --port 6310 --destfile ./results/cloud-gateway-service.exec - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CloudGatewayCentralRegistry-${{ env.JOB_ID }} @@ -352,7 +352,7 @@ jobs: # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsRegistration-${{ env.JOB_ID }} @@ -407,7 +407,7 @@ jobs: ZOSMF_APPLIEDAPARS: PH34201 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -426,7 +426,7 @@ jobs: java -jar ./scripts/jacococli.jar dump --address gateway-service --port 6300 --destfile ./results/gateway-service.exec - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsZaas-${{ env.JOB_ID }} @@ -482,7 +482,7 @@ jobs: if: always() - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsZosmfRsu2012-${{ env.JOB_ID }} @@ -523,7 +523,7 @@ jobs: ZOSMF_APPLIEDAPARS: PH12143,RSU2012,PH34201 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -535,7 +535,7 @@ jobs: -Partifactory_user=${{ secrets.ARTIFACTORY_USERNAME }} -Partifactory_password=${{ secrets.ARTIFACTORY_PASSWORD }} # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsZosmfPH34201-${{ env.JOB_ID }} @@ -587,7 +587,7 @@ jobs: -Partifactory_user=${{ secrets.ARTIFACTORY_USERNAME }} -Partifactory_password=${{ secrets.ARTIFACTORY_PASSWORD }} # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsZosmfWithoutJwt-${{ env.JOB_ID }} @@ -628,7 +628,7 @@ jobs: ZOSMF_APPLIEDAPARS: AuthenticateApar steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -640,7 +640,7 @@ jobs: -Partifactory_user=${{ secrets.ARTIFACTORY_USERNAME }} -Partifactory_password=${{ secrets.ARTIFACTORY_PASSWORD }} # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsZosmfWithoutJwtWithAuthenticateEndpoint-${{ env.JOB_ID }} @@ -696,7 +696,7 @@ jobs: if: always() - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsInternalPort-${{ env.JOB_ID }} @@ -759,7 +759,7 @@ jobs: # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsWithRedisReplica-${{ env.JOB_ID }} @@ -774,7 +774,7 @@ jobs: timeout-minutes: 15 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -827,7 +827,7 @@ jobs: # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: ContainerCITestsWithRedisSentinel-${{ env.JOB_ID }} @@ -887,7 +887,7 @@ jobs: SERVER_INTERNAL_PORT: 10027 APIML_SERVICE_DISCOVERYSERVICEURLS: https://discovery-service:10011/eureka/,https://discovery-service-2:10011/eureka/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -907,7 +907,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsHA-${{ env.JOB_ID }} @@ -968,7 +968,7 @@ jobs: APIML_ROUTING_INSTANCEIDHEADER: true APIML_LOADBALANCER_DISTRIBUTE: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1002,7 +1002,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: LbHaTests-${{ env.JOB_ID }} @@ -1052,7 +1052,7 @@ jobs: SERVER_INTERNAL_PORT: 10027 APIML_SERVICE_DISCOVERYSERVICEURLS: https://discovery-service:10011/eureka/,https://discovery-service-2:10011/eureka/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1072,7 +1072,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsDiscoveryChaoticHA-${{ env.JOB_ID }} @@ -1122,7 +1122,7 @@ jobs: SERVER_INTERNAL_PORT: 10027 APIML_SERVICE_DISCOVERYSERVICEURLS: https://discovery-service:10011/eureka/,https://discovery-service-2:10011/eureka/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1142,7 +1142,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsGatewayChaoticHA-${{ env.JOB_ID }} @@ -1196,7 +1196,7 @@ jobs: SERVER_INTERNAL_PORT: 10027 APIML_SERVICE_DISCOVERYSERVICEURLS: https://discovery-service:10011/eureka/,https://discovery-service-2:10011/eureka/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1216,7 +1216,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsDiscoverableClientChaoticHA-${{ env.JOB_ID }} @@ -1270,7 +1270,7 @@ jobs: SERVER_INTERNAL_PORT: 10027 APIML_SERVICE_DISCOVERYSERVICEURLS: https://discovery-service:10011/eureka/,https://discovery-service-2:10011/eureka/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1297,7 +1297,7 @@ jobs: chmod 755 -R .gradle # Coverage results are not stored in this job as it would not provide much additional data - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsWebSocketChaoticHA-${{ env.JOB_ID }} @@ -1356,7 +1356,7 @@ jobs: ZOSMF_APPLIEDAPARS: AuthenticateApar steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1371,7 +1371,7 @@ jobs: if: always() - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsWithInfinispan-${{ env.JOB_ID }} @@ -1418,7 +1418,7 @@ jobs: image: ghcr.io/balhar-jakub/metrics-service:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} - uses: ./.github/actions/setup @@ -1459,13 +1459,13 @@ jobs: cd metrics-service-ui/frontend npm run cy:e2e:ci - name: Upload screenshots API Catalog - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: cypress-snapshots path: api-catalog-ui/frontend/cypress/screenshots - name: Upload screenshots Metrics service - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: cypress-snapshots @@ -1496,7 +1496,7 @@ jobs: mock-services: image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -1508,7 +1508,7 @@ jobs: -Partifactory_user=${{ secrets.ARTIFACTORY_USERNAME }} -Partifactory_password=${{ secrets.ARTIFACTORY_PASSWORD }} - name: Store results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: CITestsServicePrefixReplacer-${{ env.JOB_ID }} @@ -1535,39 +1535,39 @@ jobs: 17 8 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ContainerCITests-${{ env.JOB_ID }} path: containercitests - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: CITestsWithInfinispan-${{ env.JOB_ID }} path: citestswithinfinispan - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ContainerCITestsZosmfRsu2012-${{ env.JOB_ID }} path: containercitestszosmfrsu2012 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ContainerCITestsWithRedisReplica-${{ env.JOB_ID }} path: ContainerCITestsWithRedisReplica - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ContainerCITestsWithRedisSentinel-${{ env.JOB_ID }} path: ContainerCITestsWithRedisSentinel - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ContainerCITestsInternalPort-${{ env.JOB_ID }} path: containercitestsinternalport - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: CloudGatewayProxy-${{ env.JOB_ID }} path: cloudgatewayproxy - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: CITestsWebSocketChaoticHA-${{ env.JOB_ID }} path: citestswebsocketchaoticha - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: CloudGatewayServiceRouting-${{ env.JOB_ID }} path: cloudgatewayservicerouting diff --git a/.gitignore b/.gitignore index ad9b9e7cfc..9071b7f9ea 100644 --- a/.gitignore +++ b/.gitignore @@ -117,7 +117,11 @@ invalidated*.index onboarding-enabler-micronaut/target/ onboarding-enabler-micronaut/out/ onboarding-enabler-nodejs-sample-app/tools/ - +onboarding-enabler-nodejs/coverage/ +onboarding-enabler-nodejs/lib/ file/ zowe-cli-id-federation-plugin/*.jcl + +data/* +index/* diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/api-catalog-ui/frontend/.npmrc b/api-catalog-ui/frontend/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/api-catalog-ui/frontend/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/api-catalog-ui/frontend/package-lock.json b/api-catalog-ui/frontend/package-lock.json index 5d7819d142..b0f0fe5f4c 100644 --- a/api-catalog-ui/frontend/package-lock.json +++ b/api-catalog-ui/frontend/package-lock.json @@ -19,7 +19,7 @@ "@mui/material": "5.15.18", "@react-loadable/revised": "1.5.0", "@types/enzyme": "3.10.18", - "@types/jest": "29.5.13", + "@types/jest": "29.5.14", "@types/react": "18.2.79", "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "agentkeepalive": "4.5.0", @@ -67,7 +67,7 @@ "ajv": "8.13.0", "ansi-regex": "5.0.1", "body-parser": "1.20.3", - "caniuse-lite": "1.0.30001669", + "caniuse-lite": "1.0.30001692", "concurrently": "5.3.0", "cors": "2.8.5", "cross-env": "7.0.3", @@ -84,7 +84,7 @@ "eslint-plugin-jsx-a11y": "6.6.0", "eslint-plugin-prettier": "3.4.1", "eslint-plugin-react": "7.30.1", - "express": "4.21.1", + "express": "4.21.2", "html-loader": "4.2.0", "jest": "29.7.0", "jest-environment-enzyme": "7.1.2", @@ -94,7 +94,7 @@ "jest-mock": "29.7.0", "jest-watch-typeahead": "2.2.2", "json-schema": "0.4.0", - "mini-css-extract-plugin": "2.9.1", + "mini-css-extract-plugin": "2.9.2", "nodemon": "2.0.22", "nth-check": "2.1.1", "prettier": "2.8.8", @@ -103,10 +103,10 @@ "react-app-rewired": "2.2.1", "react-error-overlay": "6.0.11", "react-scripts": "5.0.1", - "redux-mock-store": "1.5.4", + "redux-mock-store": "1.5.5", "rimraf": "3.0.2", "source-map-explorer": "2.5.3", - "start-server-and-test": "2.0.8", + "start-server-and-test": "2.0.9", "tmpl": "1.0.5", "yaml": "1.10.2" }, @@ -5405,9 +5405,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.13", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/@types/jest/-/jest-29.5.13.tgz", - "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", + "version": "29.5.14", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -6664,9 +6664,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -7412,9 +7412,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001692", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", + "integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", "funding": [ { "type": "opencollective", @@ -8084,9 +8084,9 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie/-/cookie-0.7.0.tgz", + "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==", "engines": { "node": ">= 0.6" } @@ -8944,11 +8944,11 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -8959,6 +8959,11 @@ } } }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/decamelize/-/decamelize-1.2.0.tgz", @@ -10859,9 +10864,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -10883,7 +10888,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -10898,6 +10903,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/cookie": { @@ -10933,45 +10942,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/extend/-/extend-3.0.2.tgz", @@ -18053,9 +18023,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.9.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", - "integrity": "sha512-+Vyi+GCCOHnrJ2VPS+6aPoXN2k2jgUzDRhTFLjjTBn23qyXJXkjUWQgTL+mXpF5/A8ixLdCc6kWsoeOjKGejKQ==", + "version": "2.9.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", "dev": true, "dependencies": { "schema-utils": "^4.0.0", @@ -19025,10 +18995,17 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "dev": true + "version": "1.9.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/path-type": { "version": "4.0.0", @@ -21161,19 +21138,6 @@ "react": ">=15" } }, - "node_modules/react-router/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/react-router/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/react-router/node_modules/react-is": { "version": "16.13.1", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/react-is/-/react-is-16.13.1.tgz", @@ -23289,12 +23253,15 @@ } }, "node_modules/redux-mock-store": { - "version": "1.5.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", - "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", + "version": "1.5.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/redux-mock-store/-/redux-mock-store-1.5.5.tgz", + "integrity": "sha512-YxX+ofKUTQkZE4HbhYG4kKGr7oCTJfB0GLy7bSeqx86GLpGirrbUWstMnqXkqHNaQpcnbMGbof2dYs5KsPE6Zg==", "dev": true, "dependencies": { "lodash.isplainobject": "^4.0.6" + }, + "peerDependencies": { + "redux": "*" } }, "node_modules/redux-observable": { @@ -24357,9 +24324,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -24522,21 +24489,6 @@ "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/serve-static/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -24546,45 +24498,6 @@ "node": ">= 0.8" } }, - "node_modules/serve-static/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serve-static/node_modules/send": { - "version": "0.19.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -25390,15 +25303,15 @@ "dev": true }, "node_modules/start-server-and-test": { - "version": "2.0.8", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/start-server-and-test/-/start-server-and-test-2.0.8.tgz", - "integrity": "sha512-v2fV6NV2F7tL1ocwfI4Wpait+IKjRbT5l3ZZ+ZikXdMLmxYsS8ynGAsCQAUVXkVyGyS+UibsRnvgHkMvJIvCsw==", + "version": "2.0.9", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/start-server-and-test/-/start-server-and-test-2.0.9.tgz", + "integrity": "sha512-DDceIvc4wdpr+z3Aqkot2QMho8TcUBh5qH0wEHDpEexBTzlheOcmh53d3dExABY4J5C7qS2UbSXqRWLtxpbWIQ==", "dev": true, "dependencies": { "arg": "^5.0.2", "bluebird": "3.7.2", "check-more-types": "2.24.0", - "debug": "4.3.7", + "debug": "4.4.0", "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", @@ -25413,23 +25326,6 @@ "node": ">=16" } }, - "node_modules/start-server-and-test/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/start-server-and-test/node_modules/execa": { "version": "5.1.1", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/execa/-/execa-5.1.1.tgz", @@ -25474,12 +25370,6 @@ "node": ">=10.17.0" } }, - "node_modules/start-server-and-test/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/static-eval": { "version": "2.0.2", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/static-eval/-/static-eval-2.0.2.tgz", diff --git a/api-catalog-ui/frontend/package.json b/api-catalog-ui/frontend/package.json index e43b3ec255..96f92f2988 100644 --- a/api-catalog-ui/frontend/package.json +++ b/api-catalog-ui/frontend/package.json @@ -15,7 +15,7 @@ "@mui/material": "5.15.18", "@react-loadable/revised": "1.5.0", "@types/enzyme": "3.10.18", - "@types/jest": "29.5.13", + "@types/jest": "29.5.14", "@types/react": "18.2.79", "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "agentkeepalive": "4.5.0", @@ -87,7 +87,7 @@ "ajv": "8.13.0", "ansi-regex": "5.0.1", "body-parser": "1.20.3", - "caniuse-lite": "1.0.30001669", + "caniuse-lite": "1.0.30001692", "concurrently": "5.3.0", "cors": "2.8.5", "cross-env": "7.0.3", @@ -104,7 +104,7 @@ "eslint-plugin-jsx-a11y": "6.6.0", "eslint-plugin-prettier": "3.4.1", "eslint-plugin-react": "7.30.1", - "express": "4.21.1", + "express": "4.21.2", "html-loader": "4.2.0", "jest": "29.7.0", "jest-environment-enzyme": "7.1.2", @@ -114,7 +114,7 @@ "jest-mock": "29.7.0", "jest-watch-typeahead": "2.2.2", "json-schema": "0.4.0", - "mini-css-extract-plugin": "2.9.1", + "mini-css-extract-plugin": "2.9.2", "nodemon": "2.0.22", "nth-check": "2.1.1", "prettier": "2.8.8", @@ -123,10 +123,10 @@ "react-app-rewired": "2.2.1", "react-error-overlay": "6.0.11", "react-scripts": "5.0.1", - "redux-mock-store": "1.5.4", + "redux-mock-store": "1.5.5", "rimraf": "3.0.2", "source-map-explorer": "2.5.3", - "start-server-and-test": "2.0.8", + "start-server-and-test": "2.0.9", "tmpl": "1.0.5", "yaml": "1.10.2" }, @@ -144,7 +144,9 @@ "dompurify": "3.1.7", "serve-static": "1.16.2", "body-parser": "1.20.3", - "axios": "1.7.7" + "axios": "1.7.9", + "path-to-regexp": "1.9.0", + "cookie": "0.7.0" }, "engines": { "npm": "=9.3.1", diff --git a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/WebSecurity.java b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/WebSecurity.java index 98e772ac25..c89696e9c3 100644 --- a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/WebSecurity.java +++ b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/config/WebSecurity.java @@ -24,6 +24,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.core.GrantedAuthority; @@ -31,21 +32,11 @@ import org.springframework.security.core.userdetails.ReactiveUserDetailsService; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.*; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository; -import org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver; -import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository; -import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver; -import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.server.*; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; @@ -59,22 +50,16 @@ import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; import org.zowe.apiml.cloudgatewayservice.config.oidc.ClientConfiguration; import org.zowe.apiml.product.constants.CoreService; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; - import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -424,4 +409,24 @@ public Mono removeAuthorizationRequest(ServerWebExch } + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + WebFilter writeableHeaders() { + return (exchange, chain) -> { + HttpHeaders writeableHeaders = HttpHeaders.writableHttpHeaders( + exchange.getRequest().getHeaders()); + ServerHttpRequestDecorator writeableRequest = new ServerHttpRequestDecorator( + exchange.getRequest()) { + @Override + public HttpHeaders getHeaders() { + return writeableHeaders; + } + }; + ServerWebExchange writeableExchange = exchange.mutate() + .request(writeableRequest) + .build(); + return chain.filter(writeableExchange); + }; + } + } diff --git a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/filters/RequestAttributesProvider.java b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/filters/RequestAttributesProvider.java index 6568accb85..b78e096f9d 100644 --- a/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/filters/RequestAttributesProvider.java +++ b/cloud-gateway-service/src/main/java/org/zowe/apiml/cloudgatewayservice/filters/RequestAttributesProvider.java @@ -17,6 +17,7 @@ import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.server.reactive.AbstractServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; @@ -27,8 +28,18 @@ @Component public class RequestAttributesProvider implements WebFilter, GlobalFilter, Ordered { + private R getRequest(ServerWebExchange exchange) { + Object request = exchange.getRequest(); + while (request instanceof ServerHttpRequestDecorator) { + Object delegatedRequest = ((ServerHttpRequestDecorator) request).getDelegate(); + if (request == delegatedRequest) break; + request = delegatedRequest; + } + return (R) request; + } + private void copyAttributes(ServerWebExchange exchange) { - AbstractServerHttpRequest request = (AbstractServerHttpRequest) exchange.getRequest(); + AbstractServerHttpRequest request = getRequest(exchange); RequestFacade requestFacade; try { requestFacade = request.getNativeRequest(); diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 64e9c926b4..3f02ac2346 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -13,8 +13,8 @@ dependencyResolutionManagement { version('springCloudCB', '2.1.8') version('springCloudGateway', '3.1.9') version('springSecurity') { - strictly '[5.8.13,6.0.0[' - prefer '5.8.13' + strictly '[5.8.16,6.0.0[' + prefer '5.8.16' } version('springFramework') { strictly '[5.3.39,6.0.0[' @@ -27,11 +27,11 @@ dependencyResolutionManagement { version('zosUtils', '2.0.5') version('archaius', '0.7.12') version('awaitility', '4.2.2') - version('awsJavaSdk', '1.12.774') + version('awsJavaSdk', '1.12.780') version('bouncyCastle', '1.78.1') // forced version in root gradle.build file. Version 3.x requieres Java 11 version('caffeine', '2.9.3') - version('commonsCodec', '1.17.1') + version('commonsCodec', '1.17.2') version('commonsConfiguration', '1.10') version('commonsLang3', '3.16.0') version('commonsLogging', '1.3.4') @@ -41,7 +41,7 @@ dependencyResolutionManagement { version('ehCache', '3.10.8') version('eureka', '1.10.18') version('findBugs', '3.0.2') - version('githubClassgraph', '4.8.177') + version('githubClassgraph', '4.8.179') version('gradleGitProperties', '2.2.4') // Used in classpath dependencies version('gradleNode', '3.6.0') // Used in classpath dependencies version('gson', '2.11.0') @@ -64,7 +64,7 @@ dependencyResolutionManagement { version('jaxbApi', '2.3.1') version('jersey', '2.44') version('jerseySun', '1.19.4') - version('jettyWebSocketClient', '9.4.56.v20240826') + version('jettyWebSocketClient', '9.4.57.v20241219') version('jettison', '1.5.4') version('jjwt', '0.11.5') version('jjwtFull', '0.9.1') @@ -86,7 +86,7 @@ dependencyResolutionManagement { strictly '[1.2.13, 1.3[' prefer '1.2.13' } - version('lombok', '1.18.34') + version('lombok', '1.18.36') version('mockitoCore') { // version 5.x requires Java 11 strictly '[4.11.0, 5.0.0[' @@ -99,7 +99,7 @@ dependencyResolutionManagement { } version('netflixCommonsUtil', '0.3.0') version('netflixServo', '0.13.2') - version('netty', '4.1.114.Final') + version('netty', '4.1.116.Final') version('nettyReactor', '1.1.23') version('nimbusJoseJwt', '9.40') version('openApiDiff', '2.0.1') @@ -124,20 +124,20 @@ dependencyResolutionManagement { strictly '[1.6.15, 1.7.0[' prefer '1.6.15' } - version('swagger3Core', '2.2.25') - version('swagger3Parser', '2.1.22') + version('swagger3Core', '2.2.27') + version('swagger3Parser', '2.1.24') version('swaggerCore', '1.6.14') version('swaggerInflector', '2.0.12') - version('swaggerJaxrs2', '2.2.25') - version('thymeleaf', '3.1.2.RELEASE') - version('tomcat', '9.0.96') - version('velocity', '2.4') + version('swaggerJaxrs2', '2.2.27') + version('thymeleaf', '3.1.3.RELEASE') + version('tomcat', '9.0.98') + version('velocity', '2.4.1') version('woodstoxCore', '6.7.0') version('woodstoxStax2', '4.2.2') version('xstream') { // older versions are vulnerable to CVE-2022-40151, CVE-2022-40152, and CVE-2022-41966 - strictly '[1.4.20,2.0[' - prefer '1.4.20' + strictly '[1.4.21,2.0[' + prefer '1.4.21' } // version 6.x is not compatible with gradleGitProperties and requires Java 11 diff --git a/metrics-service-ui/frontend/.npmrc b/metrics-service-ui/frontend/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/metrics-service-ui/frontend/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/metrics-service-ui/frontend/package-lock.json b/metrics-service-ui/frontend/package-lock.json index fca17f58b1..baac4e7f75 100644 --- a/metrics-service-ui/frontend/package-lock.json +++ b/metrics-service-ui/frontend/package-lock.json @@ -11,7 +11,7 @@ "@material-ui/core": "4.12.4", "@material-ui/icons": "4.11.3", "@wojtekmaj/enzyme-adapter-react-17": "0.6.7", - "axios": "1.7.7", + "axios": "1.7.9", "history": "4.10.1", "lodash": "4.17.21", "loglevel": "1.7.1", @@ -55,7 +55,7 @@ "eslint-plugin-jsx-a11y": "6.6.0", "eslint-plugin-prettier": "3.4.1", "eslint-plugin-react": "7.30.1", - "express": "4.21.1", + "express": "4.21.2", "jest": "29.7.0", "jest-enzyme": "7.1.2", "jest-html-reporter": "3.10.2", @@ -65,7 +65,7 @@ "nodemon": "2.0.22", "prettier": "2.3.0", "react-scripts": "5.0.1", - "redux-mock-store": "1.5.4" + "redux-mock-store": "1.5.5" }, "engines": { "node": "=18.14.0", @@ -5224,6 +5224,7 @@ }, "node_modules/array.prototype.filter": { "version": "1.0.2", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -5241,6 +5242,7 @@ }, "node_modules/array.prototype.flat": { "version": "1.3.1", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -5424,9 +5426,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -5447,9 +5449,9 @@ } }, "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5943,6 +5945,7 @@ }, "node_modules/boolbase": { "version": "1.0.0", + "dev": true, "license": "ISC" }, "node_modules/brace-expansion": { @@ -6232,6 +6235,7 @@ }, "node_modules/cheerio": { "version": "1.0.0-rc.12", + "dev": true, "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", @@ -6251,6 +6255,7 @@ }, "node_modules/cheerio-select": { "version": "2.1.0", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -7121,6 +7126,7 @@ }, "node_modules/css-select": { "version": "5.1.0", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -7168,6 +7174,7 @@ }, "node_modules/css-what": { "version": "6.1.0", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -7861,6 +7868,7 @@ }, "node_modules/discontinuous-range": { "version": "1.0.0", + "dev": true, "license": "MIT" }, "node_modules/dlv": { @@ -7922,6 +7930,7 @@ }, "node_modules/dom-serializer": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", @@ -7934,6 +7943,7 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "dev": true, "funding": [ { "type": "github", @@ -7963,6 +7973,7 @@ }, "node_modules/domhandler": { "version": "5.0.3", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" @@ -7976,6 +7987,7 @@ }, "node_modules/domutils": { "version": "3.0.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -8114,6 +8126,7 @@ }, "node_modules/entities": { "version": "4.4.0", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -8124,6 +8137,7 @@ }, "node_modules/enzyme": { "version": "3.11.0", + "dev": true, "license": "MIT", "dependencies": { "array.prototype.flat": "^1.2.3", @@ -8260,6 +8274,7 @@ }, "node_modules/es-array-method-boxes-properly": { "version": "1.0.0", + "dev": true, "license": "MIT" }, "node_modules/es-define-property": { @@ -8319,6 +8334,7 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.0", + "dev": true, "license": "MIT", "dependencies": { "has": "^1.0.3" @@ -9361,9 +9377,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -9385,7 +9401,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -9400,6 +9416,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -10641,6 +10661,7 @@ }, "node_modules/html-element-map": { "version": "1.3.1", + "dev": true, "license": "MIT", "dependencies": { "array.prototype.filter": "^1.0.0", @@ -10723,6 +10744,7 @@ }, "node_modules/htmlparser2": { "version": "8.0.1", + "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -11452,6 +11474,7 @@ }, "node_modules/is-subset": { "version": "0.1.1", + "dev": true, "license": "MIT" }, "node_modules/is-symbol": { @@ -15657,10 +15680,12 @@ }, "node_modules/lodash.escape": { "version": "4.0.1", + "dev": true, "license": "MIT" }, "node_modules/lodash.flattendeep": { "version": "4.4.0", + "dev": true, "license": "MIT" }, "node_modules/lodash.isarguments": { @@ -15675,6 +15700,7 @@ }, "node_modules/lodash.isequal": { "version": "4.5.0", + "dev": true, "license": "MIT" }, "node_modules/lodash.isplainobject": { @@ -16161,6 +16187,7 @@ }, "node_modules/moo": { "version": "0.5.2", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/ms": { @@ -16237,6 +16264,7 @@ }, "node_modules/nearley": { "version": "2.20.1", + "dev": true, "license": "MIT", "dependencies": { "commander": "^2.19.0", @@ -16257,6 +16285,7 @@ }, "node_modules/nearley/node_modules/commander": { "version": "2.20.3", + "dev": true, "license": "MIT" }, "node_modules/negotiator": { @@ -16422,6 +16451,7 @@ }, "node_modules/nth-check": { "version": "2.0.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -16591,6 +16621,7 @@ }, "node_modules/object.entries": { "version": "1.1.6", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -16658,6 +16689,7 @@ }, "node_modules/object.values": { "version": "1.1.6", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -16862,6 +16894,7 @@ }, "node_modules/parse5": { "version": "7.1.2", + "dev": true, "license": "MIT", "dependencies": { "entities": "^4.4.0" @@ -16872,6 +16905,7 @@ }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "7.0.0", + "dev": true, "license": "MIT", "dependencies": { "domhandler": "^5.0.2", @@ -16936,9 +16970,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "node_modules/path-type": { @@ -16956,6 +16990,7 @@ }, "node_modules/performance-now": { "version": "2.1.0", + "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -18580,6 +18615,7 @@ }, "node_modules/raf": { "version": "3.4.1", + "dev": true, "license": "MIT", "dependencies": { "performance-now": "^2.1.0" @@ -18587,10 +18623,12 @@ }, "node_modules/railroad-diagrams": { "version": "1.0.0", + "dev": true, "license": "CC0-1.0" }, "node_modules/randexp": { "version": "0.4.6", + "dev": true, "license": "MIT", "dependencies": { "discontinuous-range": "1.0.0", @@ -20872,11 +20910,15 @@ } }, "node_modules/redux-mock-store": { - "version": "1.5.4", + "version": "1.5.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/redux-mock-store/-/redux-mock-store-1.5.5.tgz", + "integrity": "sha512-YxX+ofKUTQkZE4HbhYG4kKGr7oCTJfB0GLy7bSeqx86GLpGirrbUWstMnqXkqHNaQpcnbMGbof2dYs5KsPE6Zg==", "dev": true, - "license": "MIT", "dependencies": { "lodash.isplainobject": "^4.0.6" + }, + "peerDependencies": { + "redux": "*" } }, "node_modules/redux-observable": { @@ -21283,6 +21325,7 @@ }, "node_modules/ret": { "version": "0.1.15", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12" @@ -21363,6 +21406,7 @@ }, "node_modules/rst-selector-parser": { "version": "2.2.3", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "lodash.flattendeep": "^4.4.0", @@ -22784,6 +22828,7 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.7", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -23713,20 +23758,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "license": "MIT", @@ -26181,13 +26212,11 @@ }, "@csstools/postcss-unset-value": { "version": "1.0.2", - "dev": true, - "requires": {} + "dev": true }, "@csstools/selector-specificity": { "version": "2.1.1", - "dev": true, - "requires": {} + "dev": true }, "@cypress/request": { "version": "3.0.1", @@ -26956,8 +26985,7 @@ } }, "@material-ui/types": { - "version": "5.1.0", - "requires": {} + "version": "5.1.0" }, "@material-ui/utils": { "version": "4.11.3", @@ -28043,8 +28071,7 @@ }, "acorn-jsx": { "version": "5.3.2", - "dev": true, - "requires": {} + "dev": true }, "acorn-node": { "version": "1.8.2", @@ -28125,8 +28152,7 @@ }, "ajv-keywords": { "version": "3.5.2", - "dev": true, - "requires": {} + "dev": true }, "ansi-colors": { "version": "4.1.3", @@ -28221,6 +28247,7 @@ }, "array.prototype.filter": { "version": "1.0.2", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -28231,6 +28258,7 @@ }, "array.prototype.flat": { "version": "1.3.1", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -28329,9 +28357,9 @@ "dev": true }, "axios": { - "version": "1.7.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "requires": { "follow-redirects": "1.15.9", "form-data": "^4.0.0", @@ -28339,9 +28367,9 @@ }, "dependencies": { "form-data": { - "version": "4.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -28503,8 +28531,7 @@ }, "babel-plugin-named-asset-import": { "version": "0.3.8", - "dev": true, - "requires": {} + "dev": true }, "babel-plugin-polyfill-corejs2": { "version": "0.3.3", @@ -28717,7 +28744,8 @@ } }, "boolbase": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "brace-expansion": { "version": "1.1.11", @@ -28888,6 +28916,7 @@ }, "cheerio": { "version": "1.0.0-rc.12", + "dev": true, "requires": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", @@ -28900,6 +28929,7 @@ }, "cheerio-select": { "version": "2.1.0", + "dev": true, "requires": { "boolbase": "^1.0.0", "css-select": "^5.1.0", @@ -29356,8 +29386,7 @@ }, "css-declaration-sorter": { "version": "6.3.1", - "dev": true, - "requires": {} + "dev": true }, "css-has-pseudo": { "version": "3.0.4", @@ -29442,11 +29471,11 @@ }, "css-prefers-color-scheme": { "version": "6.0.3", - "dev": true, - "requires": {} + "dev": true }, "css-select": { "version": "5.1.0", + "dev": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -29481,7 +29510,8 @@ } }, "css-what": { - "version": "6.1.0" + "version": "6.1.0", + "dev": true }, "css.escape": { "version": "1.5.1", @@ -29541,8 +29571,7 @@ }, "cssnano-utils": { "version": "3.1.0", - "dev": true, - "requires": {} + "dev": true }, "csso": { "version": "4.2.0", @@ -29944,7 +29973,8 @@ } }, "discontinuous-range": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "dlv": { "version": "1.1.3", @@ -29993,6 +30023,7 @@ }, "dom-serializer": { "version": "2.0.0", + "dev": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -30000,7 +30031,8 @@ } }, "domelementtype": { - "version": "2.3.0" + "version": "2.3.0", + "dev": true }, "domexception": { "version": "2.0.1", @@ -30017,12 +30049,14 @@ }, "domhandler": { "version": "5.0.3", + "dev": true, "requires": { "domelementtype": "^2.3.0" } }, "domutils": { "version": "3.0.1", + "dev": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -30117,10 +30151,12 @@ } }, "entities": { - "version": "4.4.0" + "version": "4.4.0", + "dev": true }, "enzyme": { "version": "3.11.0", + "dev": true, "requires": { "array.prototype.flat": "^1.2.3", "cheerio": "^1.0.0-rc.3", @@ -30229,7 +30265,8 @@ } }, "es-array-method-boxes-properly": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "es-define-property": { "version": "1.0.0", @@ -30273,6 +30310,7 @@ }, "es-shim-unscopables": { "version": "1.0.0", + "dev": true, "requires": { "has": "^1.0.3" } @@ -30494,8 +30532,7 @@ }, "eslint-config-prettier": { "version": "8.3.0", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.7", @@ -30541,8 +30578,7 @@ }, "eslint-plugin-header": { "version": "3.1.1", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-import": { "version": "2.26.0", @@ -30668,8 +30704,7 @@ }, "eslint-plugin-react-hooks": { "version": "4.6.0", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-testing-library": { "version": "5.10.0", @@ -30944,9 +30979,9 @@ } }, "express": { - "version": "4.21.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "requires": { "accepts": "~1.3.8", @@ -30968,7 +31003,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -31801,6 +31836,7 @@ }, "html-element-map": { "version": "1.3.1", + "dev": true, "requires": { "array.prototype.filter": "^1.0.0", "call-bind": "^1.0.2" @@ -31853,6 +31889,7 @@ }, "htmlparser2": { "version": "8.0.1", + "dev": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -31963,8 +32000,7 @@ }, "icss-utils": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "idb": { "version": "7.1.1", @@ -32263,7 +32299,8 @@ } }, "is-subset": { - "version": "0.1.1" + "version": "0.1.1", + "dev": true }, "is-symbol": { "version": "1.0.4", @@ -33116,8 +33153,7 @@ "version": "1.5.1", "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/dedent/-/dedent-1.5.1.tgz", "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", - "dev": true, - "requires": {} + "dev": true }, "has-flag": { "version": "4.0.0", @@ -34158,8 +34194,7 @@ }, "jest-pnp-resolver": { "version": "1.2.3", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "29.6.3", @@ -35266,10 +35301,12 @@ "dev": true }, "lodash.escape": { - "version": "4.0.1" + "version": "4.0.1", + "dev": true }, "lodash.flattendeep": { - "version": "4.4.0" + "version": "4.4.0", + "dev": true }, "lodash.isarguments": { "version": "3.1.0", @@ -35280,7 +35317,8 @@ "dev": true }, "lodash.isequal": { - "version": "4.5.0" + "version": "4.5.0", + "dev": true }, "lodash.isplainobject": { "version": "4.0.6", @@ -35590,7 +35628,8 @@ "dev": true }, "moo": { - "version": "0.5.2" + "version": "0.5.2", + "dev": true }, "ms": { "version": "2.1.2", @@ -35642,6 +35681,7 @@ }, "nearley": { "version": "2.20.1", + "dev": true, "requires": { "commander": "^2.19.0", "moo": "^0.5.0", @@ -35650,7 +35690,8 @@ }, "dependencies": { "commander": { - "version": "2.20.3" + "version": "2.20.3", + "dev": true } } }, @@ -35769,6 +35810,7 @@ }, "nth-check": { "version": "2.0.1", + "dev": true, "requires": { "boolbase": "^1.0.0" } @@ -35875,6 +35917,7 @@ }, "object.entries": { "version": "1.1.6", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -35916,6 +35959,7 @@ }, "object.values": { "version": "1.1.6", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -36044,12 +36088,14 @@ }, "parse5": { "version": "7.1.2", + "dev": true, "requires": { "entities": "^4.4.0" } }, "parse5-htmlparser2-tree-adapter": { "version": "7.0.0", + "dev": true, "requires": { "domhandler": "^5.0.2", "parse5": "^7.0.0" @@ -36088,9 +36134,9 @@ "dev": true }, "path-to-regexp": { - "version": "0.1.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "path-type": { @@ -36102,7 +36148,8 @@ "dev": true }, "performance-now": { - "version": "2.1.0" + "version": "2.1.0", + "dev": true }, "picocolors": { "version": "1.0.0", @@ -36189,8 +36236,7 @@ }, "postcss-browser-comments": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-calc": { "version": "8.2.4", @@ -36276,23 +36322,19 @@ }, "postcss-discard-comments": { "version": "5.1.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-duplicates": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-empty": { "version": "5.1.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-overridden": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-double-position-gradients": { "version": "3.1.2", @@ -36311,8 +36353,7 @@ }, "postcss-flexbugs-fixes": { "version": "5.0.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-focus-visible": { "version": "6.0.4", @@ -36330,13 +36371,11 @@ }, "postcss-font-variant": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-gap-properties": { "version": "3.0.5", - "dev": true, - "requires": {} + "dev": true }, "postcss-image-set-function": { "version": "4.0.7", @@ -36356,8 +36395,7 @@ }, "postcss-initial": { "version": "4.0.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-js": { "version": "4.0.0", @@ -36415,13 +36453,11 @@ }, "postcss-logical": { "version": "5.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-media-minmax": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-merge-longhand": { "version": "5.1.7", @@ -36475,8 +36511,7 @@ }, "postcss-modules-extract-imports": { "version": "3.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -36527,8 +36562,7 @@ }, "postcss-normalize-charset": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -36590,8 +36624,7 @@ }, "postcss-opacity-percentage": { "version": "1.1.3", - "dev": true, - "requires": {} + "dev": true }, "postcss-ordered-values": { "version": "5.1.3", @@ -36610,8 +36643,7 @@ }, "postcss-page-break": { "version": "3.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-place": { "version": "7.0.5", @@ -36699,8 +36731,7 @@ }, "postcss-replace-overflow-wrap": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-selector-not": { "version": "6.0.1", @@ -36962,15 +36993,18 @@ }, "raf": { "version": "3.4.1", + "dev": true, "requires": { "performance-now": "^2.1.0" } }, "railroad-diagrams": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "randexp": { "version": "0.4.6", + "dev": true, "requires": { "discontinuous-range": "1.0.0", "ret": "~0.1.10" @@ -38520,7 +38554,9 @@ } }, "redux-mock-store": { - "version": "1.5.4", + "version": "1.5.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/redux-mock-store/-/redux-mock-store-1.5.5.tgz", + "integrity": "sha512-YxX+ofKUTQkZE4HbhYG4kKGr7oCTJfB0GLy7bSeqx86GLpGirrbUWstMnqXkqHNaQpcnbMGbof2dYs5KsPE6Zg==", "dev": true, "requires": { "lodash.isplainobject": "^4.0.6" @@ -38539,8 +38575,7 @@ } }, "redux-persist": { - "version": "6.0.0", - "requires": {} + "version": "6.0.0" }, "redux-persist-transform-filter": { "version": "0.0.22", @@ -38798,7 +38833,8 @@ } }, "ret": { - "version": "0.1.15" + "version": "0.1.15", + "dev": true }, "retry": { "version": "0.13.1", @@ -38849,6 +38885,7 @@ }, "rst-selector-parser": { "version": "2.2.3", + "dev": true, "requires": { "lodash.flattendeep": "^4.4.0", "nearley": "^2.7.10" @@ -39860,6 +39897,7 @@ }, "string.prototype.trim": { "version": "1.2.7", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -39933,8 +39971,7 @@ }, "style-loader": { "version": "3.3.1", - "dev": true, - "requires": {} + "dev": true }, "stylehacks": { "version": "5.1.1", @@ -40458,13 +40495,6 @@ "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "4.9.5", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "peer": true - }, "unbox-primitive": { "version": "1.0.2", "requires": { @@ -40768,8 +40798,7 @@ }, "acorn-import-assertions": { "version": "1.8.0", - "dev": true, - "requires": {} + "dev": true }, "schema-utils": { "version": "3.1.1", @@ -40836,8 +40865,7 @@ }, "ws": { "version": "8.12.0", - "dev": true, - "requires": {} + "dev": true } } }, @@ -41234,8 +41262,7 @@ }, "ws": { "version": "7.5.9", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/metrics-service-ui/frontend/package.json b/metrics-service-ui/frontend/package.json index 5ce22f76a1..ff788b4188 100644 --- a/metrics-service-ui/frontend/package.json +++ b/metrics-service-ui/frontend/package.json @@ -7,7 +7,7 @@ "@material-ui/core": "4.12.4", "@material-ui/icons": "4.11.3", "@wojtekmaj/enzyme-adapter-react-17": "0.6.7", - "axios": "1.7.7", + "axios": "1.7.9", "history": "4.10.1", "lodash": "4.17.21", "loglevel": "1.7.1", @@ -50,8 +50,8 @@ "@testing-library/jest-dom": "6.1.4", "@testing-library/react": "12.1.5", "@testing-library/user-event": "13.5.0", - "redux-mock-store": "1.5.4", - "express": "4.21.1", + "redux-mock-store": "1.5.5", + "express": "4.21.2", "jest": "29.7.0", "jest-enzyme": "7.1.2", "@jest/globals": "29.7.0", diff --git a/onboarding-enabler-nodejs-sample-app/.npmrc b/onboarding-enabler-nodejs-sample-app/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/onboarding-enabler-nodejs-sample-app/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/onboarding-enabler-nodejs-sample-app/build.gradle b/onboarding-enabler-nodejs-sample-app/build.gradle index 08f269324a..dd0eea807a 100644 --- a/onboarding-enabler-nodejs-sample-app/build.gradle +++ b/onboarding-enabler-nodejs-sample-app/build.gradle @@ -17,7 +17,7 @@ node { version = libs.versions.projectNode.get() npmVersion = libs.versions.projectNpm.get() distBaseUrl = "https://nodejs.org/dist" - npmInstallCommand = "ci" + npmInstallCommand = "install" workDir = file("${project.projectDir}/tools/nodejs") npmWorkDir = file("${project.projectDir}/tools/npm") yarnWorkDir = file("${project.projectDir}/tools/yarn") diff --git a/onboarding-enabler-nodejs-sample-app/package-lock.json b/onboarding-enabler-nodejs-sample-app/package-lock.json index e89bf05b04..c1dc72bdea 100644 --- a/onboarding-enabler-nodejs-sample-app/package-lock.json +++ b/onboarding-enabler-nodejs-sample-app/package-lock.json @@ -1,1149 +1,1159 @@ { - "name": "helloworld-expressjs", - "version": "0.3.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "helloworld-expressjs", - "version": "0.3.0", - "license": "EPL-2.0", - "dependencies": { - "@zowe/apiml-onboarding-enabler-nodejs": "file:../onboarding-enabler-nodejs", - "express": "4.21.1" - }, - "engines": { - "node": "=16.19.0", - "npm": "=8.19.4" - } - }, - "node_modules/@zowe/apiml-onboarding-enabler-nodejs": { - "version": "2.17.3", - "resolved": "file:../onboarding-enabler-nodejs", - "license": "EPL-2.0", - "dependencies": { - "eureka-js-client": "^4.5.0" - }, - "engines": { - "node": "=16.19.0", - "npm": "=8.19.4" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.13.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/aws4/-/aws4-1.13.2.tgz", - "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "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.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eureka-js-client": { - "version": "4.5.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/eureka-js-client/-/eureka-js-client-4.5.0.tgz", - "integrity": "sha512-vnkrw7UPAHdJbTsjpgVJfqjr3FFJnEJNq4acRbc6s8qTAhO0LhTDkN4a/1TUYlsr480x0PWjA6jzqVGCjyWE7g==", - "dependencies": { - "async": "^2.0.1", - "js-yaml": "^3.3.1", - "lodash": "^4.13.1", - "request": "^2.83.0" - } - }, - "node_modules/express": { - "version": "4.21.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "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" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-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" + "name": "helloworld-expressjs", + "version": "0.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "helloworld-expressjs", + "version": "0.3.0", + "license": "EPL-2.0", + "dependencies": { + "@zowe/apiml-onboarding-enabler-nodejs": "file:../onboarding-enabler-nodejs", + "express": "4.21.2" + }, + "engines": { + "node": "=16.19.0", + "npm": "=8.19.4" + } + }, + "node_modules/@zowe/apiml-onboarding-enabler-nodejs": { + "version": "2.17.3", + "resolved": "file:../onboarding-enabler-nodejs", + "license": "EPL-2.0", + "dependencies": { + "eureka-js-client": "^4.5.0" + }, + "engines": { + "node": "=16.19.0", + "npm": "=8.19.4" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "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.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eureka-js-client": { + "version": "4.5.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/eureka-js-client/-/eureka-js-client-4.5.0.tgz", + "integrity": "sha512-vnkrw7UPAHdJbTsjpgVJfqjr3FFJnEJNq4acRbc6s8qTAhO0LhTDkN4a/1TUYlsr480x0PWjA6jzqVGCjyWE7g==", + "dependencies": { + "async": "^2.0.1", + "js-yaml": "^3.3.1", + "lodash": "^4.13.1", + "request": "^2.83.0" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "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" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.19.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.19.1.tgz", + "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { + "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" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/send": { - "version": "0.19.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/send/-/send-0.19.1.tgz", - "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dependencies": { - "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" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://zowe.jfrog.io/artifactory/api/npm/npm-org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } } - } } diff --git a/onboarding-enabler-nodejs-sample-app/package.json b/onboarding-enabler-nodejs-sample-app/package.json index 86897db8f8..d669e58a0c 100755 --- a/onboarding-enabler-nodejs-sample-app/package.json +++ b/onboarding-enabler-nodejs-sample-app/package.json @@ -1,31 +1,32 @@ { - "name": "helloworld-expressjs", - "version": "0.3.0", - "description": "Hello World Service in Express", - "main": "src/index.js", - "scripts": { - "start": "node src/index.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/zowe/api-layer.git" - }, - "author": "", - "license": "EPL-2.0", - "dependencies": { - "@zowe/apiml-onboarding-enabler-nodejs": "file:../onboarding-enabler-nodejs", - "express": "4.21.1" - }, - "overrides": { - "tough-cookie": "4.1.4", - "ms": "2.1.3", - "serve-static": "1.16.2", - "body-parser": "1.20.3", - "send": "0.19.1" - }, - "engines": { - "npm": "=8.19.4", - "node": "=16.19.0" - } + "name": "helloworld-expressjs", + "version": "0.3.0", + "description": "Hello World Service in Express", + "type": "module", + "main": "src/index.js", + "scripts": { + "start": "node src/index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/zowe/api-layer.git" + }, + "author": "", + "license": "EPL-2.0", + "dependencies": { + "@zowe/apiml-onboarding-enabler-nodejs": "file:../onboarding-enabler-nodejs", + "express": "4.21.2" + }, + "overrides": { + "tough-cookie": "4.1.4", + "ms": "2.1.3", + "serve-static": "1.16.2", + "body-parser": "1.20.3", + "send": "0.19.1" + }, + "engines": { + "npm": "=8.19.4", + "node": "=16.19.0" + } } diff --git a/onboarding-enabler-nodejs-sample-app/src/index.js b/onboarding-enabler-nodejs-sample-app/src/index.js index 774b23ad15..f29bb9ef73 100755 --- a/onboarding-enabler-nodejs-sample-app/src/index.js +++ b/onboarding-enabler-nodejs-sample-app/src/index.js @@ -8,9 +8,9 @@ * Copyright Contributors to the Zowe Project. */ -const express = require("express"); -const https = require("https"); -const apiLayerService = require("@zowe/apiml-onboarding-enabler-nodejs"); +import express from "express"; +import * as https from "https"; +import * as apiLayerService from "@zowe/apiml-onboarding-enabler-nodejs"; // Command-line arguments: const args = { @@ -54,7 +54,7 @@ function startHttpsService() { app.use(express.static("src/static")); // Start HTTPS server and register to Discovery Service: - tlsOptions = apiLayerService.tlsOptions; + const tlsOptions = apiLayerService.tlsOptions; httpsServer = https.createServer(tlsOptions, app); httpsServer.listen(args.port, function () { console.log(`${args.serviceId} service listening on port ${args.port}`); diff --git a/onboarding-enabler-nodejs/.babelrc b/onboarding-enabler-nodejs/.babelrc new file mode 100644 index 0000000000..002b4aa0d5 --- /dev/null +++ b/onboarding-enabler-nodejs/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env"] +} diff --git a/onboarding-enabler-nodejs/.eslintrc b/onboarding-enabler-nodejs/.eslintrc new file mode 100644 index 0000000000..acf9653adc --- /dev/null +++ b/onboarding-enabler-nodejs/.eslintrc @@ -0,0 +1,10 @@ +{ + "extends": ["airbnb-base"], + "rules": { + "no-param-reassign": [2, {"props": false}], + "consistent-return": 0 + }, + "env": { + "mocha": true + } +} diff --git a/onboarding-enabler-nodejs/.npmrc b/onboarding-enabler-nodejs/.npmrc new file mode 100644 index 0000000000..59c413d08e --- /dev/null +++ b/onboarding-enabler-nodejs/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org diff --git a/onboarding-enabler-nodejs/gulpfile.babel.js b/onboarding-enabler-nodejs/gulpfile.babel.js new file mode 100644 index 0000000000..133f3ece05 --- /dev/null +++ b/onboarding-enabler-nodejs/gulpfile.babel.js @@ -0,0 +1,64 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +import gulp from 'gulp'; +import babel from 'gulp-babel'; +import mocha from 'gulp-mocha'; +import eslint from 'gulp-eslint'; +import { Instrumenter } from 'babel-istanbul'; +import istanbul from 'gulp-istanbul'; +import env from 'gulp-env'; + +gulp.task('build', () => ( + gulp.src('src/**/*.js') + .pipe(babel()) + .pipe(gulp.dest('lib')) +)); + +gulp.task('lint', () => ( + gulp.src(['src/**/*.js', 'test/**/*.js']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failOnError()) +)); + +gulp.task('mocha', (cb) => { + const envs = env.set({ + NODE_ENV: 'test', + }); + + return gulp.src('src/**/*.js') + .pipe(envs) + .pipe(istanbul({ + instrumenter: Instrumenter, + })) // Covering files + .pipe(istanbul.hookRequire()) // Force `require` to return covered files + .on('finish', () => { + gulp.src(['test/**/*.js', '!test/integration.test.js']) + .pipe(mocha()) + .pipe(istanbul.writeReports()) + .pipe(istanbul.enforceThresholds({ thresholds: { global: 0 } })) + .pipe(envs.reset) + .on('end', cb); + }); +}); + +gulp.task('test:integration', () => ( + gulp.src('test/integration.test.js') + .pipe(mocha({ timeout: 120000 })) +)); + +gulp.task('test', gulp.series('lint', 'mocha')); + +gulp.task('test:watch', () => ( + gulp.watch(['src/**/*.js', 'test/**/*.test.js'], ['test']) +)); + +gulp.task('default', gulp.series('build')); diff --git a/onboarding-enabler-nodejs/license-checker-config.json b/onboarding-enabler-nodejs/license-checker-config.json new file mode 100644 index 0000000000..ede2e40b04 --- /dev/null +++ b/onboarding-enabler-nodejs/license-checker-config.json @@ -0,0 +1,16 @@ +{ + "license": "../.licence/EPL-2.0-licence-header.txt", + "licenseFormats": { + "ts|js": { + "prepend": "/*", + "append": " */\n", + "eachLine": { + "prepend": " * " + } + } + }, + "ignore": [ + "bin", "lib", "coverage", + ".*", "*.md", "*.gradle", "**/*.yml" + ] +} diff --git a/onboarding-enabler-nodejs/package.json b/onboarding-enabler-nodejs/package.json index 389ed6d236..fda2287dbf 100644 --- a/onboarding-enabler-nodejs/package.json +++ b/onboarding-enabler-nodejs/package.json @@ -2,10 +2,13 @@ "name": "@zowe/apiml-onboarding-enabler-nodejs", "version": "2.17.3", "description": "NodeJS enabler for Zowe API Mediation Layer", + "type": "module", "main": "src/index.js", "scripts": { - "start": "node src/index.js NODE_DEBUG=request", - "test": "echo \"Error: no test specified\" && exit 1" + "start": "node src/index.js NODE_DEBUG=*", + "prepublish": "gulp", + "test": "gulp test", + "integration": "gulp test:integration" }, "repository": { "type": "git", @@ -15,10 +18,37 @@ "license": "EPL-2.0", "homepage": ".", "dependencies": { - "eureka-js-client": "^4.5.0" + "async": "3.2.6", + "js-yaml": "4.1.0", + "lodash": "4.17.21" }, "devDependencies": { - "js-yaml": "^4.0.0" + "babel-core": "6.26.3", + "babel-istanbul": "0.12.2", + "babel-preset-env": "1.7.0", + "chai": "5.1.2", + "coveralls": "3.1.1", + "eslint": "^2.13.1", + "eslint-config-airbnb-base": "^3.0.1", + "eslint-plugin-import": "^1.16.0", + "gulp": "5.0.0", + "gulp-babel": "^7.0.0", + "gulp-env": "0.4.0", + "gulp-eslint": "6.0.0", + "gulp-istanbul": "1.1.3", + "gulp-mocha": "10.0.1", + "nock": "13.5.6", + "sinon": "19.0.2", + "sinon-chai": "4.0.0" + }, + "greenkeeper": { + "ignore": [ + "eslint", + "eslint-config-airbnb-base", + "eslint-plugin-import", + "gulp-eslint", + "gulp-mocha" + ] }, "engines": { "npm": "=8.19.4", diff --git a/onboarding-enabler-nodejs/src/AwsMetadata.js b/onboarding-enabler-nodejs/src/AwsMetadata.js new file mode 100644 index 0000000000..c789d9f33e --- /dev/null +++ b/onboarding-enabler-nodejs/src/AwsMetadata.js @@ -0,0 +1,122 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import async from 'async'; +import Logger from './Logger.js'; + +/* + Utility class for pulling AWS metadata that Eureka requires when + registering as an Amazon instance (datacenter). +*/ +export default class AwsMetadata { + constructor(config = {}) { + this.logger = config.logger || new Logger(); + this.host = config.host || '169.254.169.254'; + } + + fetchMetadata(resultsCallback) { + async.parallel({ + 'ami-id': callback => { + this.lookupMetadataKey('ami-id', callback); + }, + 'instance-id': callback => { + this.lookupMetadataKey('instance-id', callback); + }, + 'instance-type': callback => { + this.lookupMetadataKey('instance-type', callback); + }, + 'local-ipv4': callback => { + this.lookupMetadataKey('local-ipv4', callback); + }, + 'local-hostname': callback => { + this.lookupMetadataKey('local-hostname', callback); + }, + 'availability-zone': callback => { + this.lookupMetadataKey('placement/availability-zone', callback); + }, + 'public-hostname': callback => { + this.lookupMetadataKey('public-hostname', callback); + }, + 'public-ipv4': callback => { + this.lookupMetadataKey('public-ipv4', callback); + }, + mac: callback => { + this.lookupMetadataKey('mac', callback); + }, + accountId: callback => { + // the accountId is in the identity document. + this.lookupInstanceIdentity((error, identity) => { + callback(null, identity ? identity.accountId : null); + }); + }, + }, (error, results) => { + // we need the mac before we can lookup the vpcId... + this.lookupMetadataKey(`network/interfaces/macs/${results.mac}/vpc-id`, (err, vpcId) => { + results['vpc-id'] = vpcId; + this.logger.debug('Found Instance AWS Metadata', results); + const filteredResults = Object.keys(results).reduce((filtered, prop) => { + if (results[prop]) filtered[prop] = results[prop]; + return filtered; + }, {}); + resultsCallback(filteredResults); + }); + }); + } + + lookupMetadataKey(key, callback) { + fetch(`http://${this.host}/latest/meta-data/${key}`).then(response => { + let error = null; + if (!response.ok) { + error = new Error(`${response.statusCode}: ${response.statusMessage}`); + this.logger.error('Error requesting metadata key', error); + } + response.text().then(text => { + callback(null, (error || response.statusCode !== 200) ? null : text); + }); + }); + } + + lookupInstanceIdentity(callback) { + fetch(`http://${this.host}/latest/dynamic/instance-identity/document`).then(response => { + let error = null; + if (!response.ok) { + error = new Error(`${response.statusCode}: ${response.statusMessage}`); + this.logger.error('Error requesting instance identity document', error); + } + response.json().then(json => { + callback(null, (error || response.statusCode !== 200) ? null : json); + }); + }); + } +} diff --git a/onboarding-enabler-nodejs/src/ConfigClusterResolver.js b/onboarding-enabler-nodejs/src/ConfigClusterResolver.js new file mode 100644 index 0000000000..48ada81e40 --- /dev/null +++ b/onboarding-enabler-nodejs/src/ConfigClusterResolver.js @@ -0,0 +1,87 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Logger from './Logger.js'; + +/* + Locates a Eureka host using static configuration. Configuration can either be + done using a simple host and port, or a map of serviceUrls. + */ +export default class ConfigClusterResolver { + constructor(config, logger) { + this.logger = logger || new Logger(); + this.config = config; + this.serviceUrls = this.buildServiceUrls(); + } + + resolveEurekaUrl(callback, retryAttempt = 0) { + if (this.serviceUrls.length > 1 && retryAttempt > 0) { + this.serviceUrls.push(this.serviceUrls.shift()); + } + callback(null, this.serviceUrls[0]); + } + + buildServiceUrls() { + const { host, port, servicePath, ssl, + serviceUrls, preferSameZone } = this.config.eureka; + const { dataCenterInfo } = this.config.instance; + const metadata = dataCenterInfo ? dataCenterInfo.metadata : undefined; + const instanceZone = metadata ? metadata['availability-zone'] : undefined; + const urls = []; + const zones = this.getAvailabilityZones(); + if (serviceUrls) { + zones.forEach((zone) => { + if (serviceUrls[zone]) { + if (preferSameZone && instanceZone && instanceZone === zone) { + urls.unshift(...serviceUrls[zone]); + } + urls.push(...serviceUrls[zone]); + } + }); + } + if (!urls.length) { + const protocol = ssl ? 'https' : 'http'; + urls.push(`${protocol}://${host}:${port}${servicePath}`); + } + return urls; + } + + getAvailabilityZones() { + const { ec2Region, availabilityZones } = this.config.eureka; + if (ec2Region && availabilityZones && availabilityZones[ec2Region]) { + return availabilityZones[ec2Region]; + } + return ['default']; + } +} diff --git a/onboarding-enabler-nodejs/src/DnsClusterResolver.js b/onboarding-enabler-nodejs/src/DnsClusterResolver.js new file mode 100644 index 0000000000..43af4c9dda --- /dev/null +++ b/onboarding-enabler-nodejs/src/DnsClusterResolver.js @@ -0,0 +1,164 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import dns from 'dns'; +import async from 'async'; +import shuffle from 'lodash/shuffle.js'; +import xor from 'lodash/xor.js'; +import Logger from './Logger.js'; + +function noop() {} + +/* + Locates a Eureka host using DNS lookups. The DNS records are looked up by a naming + convention and TXT records must be created according to the Eureka Wiki here: + https://github.com/Netflix/eureka/wiki/Configuring-Eureka-in-AWS-Cloud + + Naming convention: txt.. + */ +export default class DnsClusterResolver { + constructor(config, logger) { + this.logger = logger || new Logger(); + this.serverList = undefined; + this.config = config; + if (!this.config.eureka.ec2Region) { + throw new Error( + 'EC2 region was undefined. ' + + 'config.eureka.ec2Region must be set to resolve Eureka using DNS records.' + ); + } + + if (this.config.eureka.clusterRefreshInterval) { + this.startClusterRefresh(); + } + } + + resolveEurekaUrl(callback, retryAttempt = 0) { + this.getCurrentCluster((err) => { + if (err) return callback(err); + + if (retryAttempt > 0) { + this.serverList.push(this.serverList.shift()); + } + const { port, servicePath, ssl } = this.config.eureka; + const protocol = ssl ? 'https' : 'http'; + callback(null, `${protocol}://${this.serverList[0]}:${port}${servicePath}`); + }); + } + + getCurrentCluster(callback) { + if (this.serverList) { + return callback(null, this.serverList); + } + this.refreshCurrentCluster((err) => { + if (err) return callback(err); + return callback(null, this.serverList); + }); + } + + startClusterRefresh() { + const refreshTimer = setInterval(() => { + this.refreshCurrentCluster((err) => { + if (err) this.logger.warn(err.message); + }); + }, this.config.eureka.clusterRefreshInterval); + refreshTimer.unref(); + } + + refreshCurrentCluster(callback = noop) { + this.resolveClusterHosts((err, hosts) => { + if (err) return callback(err); + // if the cluster is the same (aside from order), we want to maintain our order + if (xor(this.serverList, hosts).length) { + this.serverList = hosts; + this.logger.info('Eureka cluster located, hosts will be used in the following order', + this.serverList); + } else { + this.logger.debug('Eureka cluster hosts unchanged, maintaining current server list.'); + } + callback(); + }); + } + + resolveClusterHosts(callback = noop) { + const { ec2Region, host, preferSameZone } = this.config.eureka; + const { dataCenterInfo } = this.config.instance; + const metadata = dataCenterInfo ? dataCenterInfo.metadata : undefined; + const availabilityZone = metadata ? metadata['availability-zone'] : undefined; + const dnsHost = `txt.${ec2Region}.${host}`; + dns.resolveTxt(dnsHost, (err, addresses) => { + if (err) { + return callback(new Error( + `Error resolving eureka cluster for region [${ec2Region}] using DNS: [${err}]` + )); + } + const zoneRecords = [].concat(...addresses); + const dnsTasks = {}; + zoneRecords.forEach((zoneRecord) => { + dnsTasks[zoneRecord] = (cb) => { + this.resolveZoneHosts(`txt.${zoneRecord}`, cb); + }; + }); + async.parallel(dnsTasks, (error, results) => { + if (error) return callback(error); + const hosts = []; + const myZoneHosts = []; + Object.keys(results).forEach((zone) => { + if (preferSameZone && availabilityZone && zone.lastIndexOf(availabilityZone, 0) === 0) { + myZoneHosts.push(...results[zone]); + } else { + hosts.push(...results[zone]); + } + }); + const combinedHosts = [].concat(shuffle(myZoneHosts), shuffle(hosts)); + if (!combinedHosts.length) { + return callback( + new Error(`Unable to locate any Eureka hosts in any zone via DNS @ ${dnsHost}`)); + } + callback(null, combinedHosts); + }); + }); + } + + resolveZoneHosts(zoneRecord, callback) { + dns.resolveTxt(zoneRecord, (err, results) => { + if (err) { + this.logger.warn(`Failed to resolve cluster zone ${zoneRecord}`, err.message); + return callback(new Error(`Error resolving cluster zone ${zoneRecord}: [${err}]`)); + } + this.logger.debug(`Found Eureka Servers @ ${zoneRecord}`, results); + callback(null, ([].concat(...results)).filter((value) => (!!value))); + }); + } +} diff --git a/onboarding-enabler-nodejs/src/EurekaClient.js b/onboarding-enabler-nodejs/src/EurekaClient.js new file mode 100644 index 0000000000..d12068290e --- /dev/null +++ b/onboarding-enabler-nodejs/src/EurekaClient.js @@ -0,0 +1,698 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import fs from 'fs'; +import yaml from 'js-yaml'; +import lodash from 'lodash'; +const { findIndex, merge } = lodash; +import { findInstance, normalizeDelta } from './deltaUtils.js'; +import path from 'path'; +import { series, waterfall } from 'async'; +import { EventEmitter } from 'events'; + +import AwsMetadata from './AwsMetadata.js'; +import ConfigClusterResolver from './ConfigClusterResolver.js'; +import DnsClusterResolver from './DnsClusterResolver.js'; +import Logger from './Logger.js'; +import defaultConfig from './defaultConfig.js'; +import https from 'https'; + +function noop() {} + +/* + Eureka JS client + This module handles registration with a Eureka server, as well as heartbeats + for reporting instance health. +*/ + +function fileExists(file) { + try { + return fs.statSync(file); + } catch (e) { + return false; + } +} + +function getYaml(file) { + let yml = {}; + if (!fileExists(file)) { + return yml; // no configuration file + } + try { + yml = yaml.load(fs.readFileSync(file, 'utf8')); + } catch (e) { + // configuration file exists but was malformed + throw new Error(`Error loading YAML configuration file: ${file} ${e}`); + } + return yml; +} + +export default class Eureka extends EventEmitter { + constructor(config = {}) { + super(); + // Allow passing in a custom logger: + this.logger = config.logger || new Logger(); + + this.logger.debug('initializing eureka client'); + + // Load up the current working directory and the environment: + const cwd = config.cwd || process.cwd(); + const env = process.env.EUREKA_ENV || process.env.NODE_ENV || 'development'; + + const filename = config.filename || 'eureka-client'; + + // Load in the configuration files: + const defaultYml = getYaml(path.join(cwd, `${filename}.yml`)); + const envYml = getYaml(path.join(cwd, `${filename}-${env}.yml`)); + + // apply config overrides in appropriate order + this.config = merge({}, defaultConfig, defaultYml, envYml, config); + + // Validate the provided the values we need: + this.validateConfig(this.config); + + this.requestMiddleware = this.config.requestMiddleware; + + this.hasFullRegistry = false; + + if (this.amazonDataCenter) { + this.metadataClient = new AwsMetadata({ + logger: this.logger, + }); + } + + if (this.config.eureka.useDns) { + this.clusterResolver = new DnsClusterResolver(this.config, this.logger); + } else { + this.clusterResolver = new ConfigClusterResolver(this.config, this.logger); + } + + this.cache = { + app: {}, + vip: {}, + }; + } + + /* + Helper method to get the instance ID. If the datacenter is AWS, this will be the + instance-id in the metadata. Else, it's the hostName. + */ + get instanceId() { + if (this.config.instance.instanceId) { + return this.config.instance.instanceId; + } else if (this.amazonDataCenter) { + return this.config.instance.dataCenterInfo.metadata['instance-id']; + } + return this.config.instance.hostName; + } + + /* + Helper method to determine if this is an AWS datacenter. + */ + get amazonDataCenter() { + const { dataCenterInfo } = this.config.instance; + return ( + dataCenterInfo && + dataCenterInfo.name && + dataCenterInfo.name.toLowerCase() === 'amazon' + ); + } + + /* + Registers instance with Eureka, begins heartbeats, and fetches registry. + */ + start(callback = noop) { + series([ + done => { + if (this.metadataClient && this.config.eureka.fetchMetadata) { + return this.addInstanceMetadata(done); + } + done(); + }, + done => { + if (this.config.eureka.registerWithEureka) { + return this.register(done); + } + done(); + }, + done => { + if (this.config.eureka.registerWithEureka) { + this.startHeartbeats(); + } + if (this.config.eureka.fetchRegistry) { + this.startRegistryFetches(); + if (this.config.eureka.waitForRegistry) { + const waitForRegistryUpdate = (cb) => { + this.fetchRegistry(() => { + const instances = this.getInstancesByVipAddress(this.config.instance.vipAddress); + if (instances.length === 0) setTimeout(() => waitForRegistryUpdate(cb), 2000); + else cb(); + }); + }; + return waitForRegistryUpdate(done); + } + this.fetchRegistry(done); + } else { + done(); + } + }, + ], (err, ...rest) => { + if (err) { + this.logger.warn('Error starting the Eureka Client', err); + } else { + this.emit('started'); + } + callback(err, ...rest); + }); + } + + /* + De-registers instance with Eureka, stops heartbeats / registry fetches. + */ + stop(callback = noop) { + clearInterval(this.registryFetch); + if (this.config.eureka.registerWithEureka) { + clearInterval(this.heartbeat); + this.deregister(callback); + } else { + callback(); + } + } + + /* + Validates client configuration. + */ + validateConfig(config) { + function validate(namespace, key) { + if (!config[namespace][key]) { + throw new TypeError(`Missing "${namespace}.${key}" config value.`); + } + } + + if (config.eureka.registerWithEureka) { + validate('instance', 'app'); + validate('instance', 'vipAddress'); + validate('instance', 'port'); + validate('instance', 'dataCenterInfo'); + } + + if (typeof config.requestMiddleware !== 'function') { + throw new TypeError('requestMiddleware must be a function'); + } + } + + /* + Registers with the Eureka server and initializes heartbeats on registration success. + */ + register(callback = noop) { + this.config.instance.status = 'UP'; + const connectionTimeout = setTimeout(() => { + this.logger.warn('It looks like it\'s taking a while to register with ' + + 'Eureka. This usually means there is an issue connecting to the host ' + + 'specified. Start application with NODE_DEBUG=http for more logging.'); + }, 10000); + this.eurekaRequest({ + method: 'POST', + uri: this.config.instance.app, + json: true, + body: { instance: this.config.instance }, + }, (error, response, body) => { + clearTimeout(connectionTimeout); + if (!error && response.statusCode === 204) { + this.logger.info( + 'registered with eureka: ', + `${this.config.instance.app}/${this.instanceId}` + ); + this.emit('registered'); + return callback(null); + } else if (error) { + this.logger.warn('Error registering with eureka client.', error); + return callback(error); + } + return callback( + new Error(`eureka registration FAILED: status: ${response.statusCode} body: ${body}`) + ); + }); + } + + /* + De-registers with the Eureka server and stops heartbeats. + */ + deregister(callback = noop) { + this.eurekaRequest({ + method: 'DELETE', + uri: `${this.config.instance.app}/${this.instanceId}`, + }, (error, response, body) => { + if (!error && response.statusCode === 200) { + this.logger.info( + `de-registered with eureka: ${this.config.instance.app}/${this.instanceId}` + ); + this.emit('deregistered'); + return callback(null); + } else if (error) { + this.logger.warn('Error deregistering with eureka', error); + return callback(error); + } + return callback( + new Error(`eureka deregistration FAILED: status: ${response.statusCode} body: ${body}`) + ); + }); + } + + /* + Sets up heartbeats on interval for the life of the application. + Heartbeat interval by setting configuration property: eureka.heartbeatInterval + */ + startHeartbeats() { + this.heartbeat = setInterval(() => { + this.renew(); + }, this.config.eureka.heartbeatInterval); + } + + renew() { + this.eurekaRequest({ + method: 'PUT', + uri: `${this.config.instance.app}/${this.instanceId}`, + }, (error, response, body) => { + if (!error && response.statusCode === 200) { + this.logger.debug('eureka heartbeat success'); + this.emit('heartbeat'); + } else if (!error && response.statusCode === 404) { + this.logger.warn('eureka heartbeat FAILED, Re-registering app'); + this.register(); + } else { + if (error) { + this.logger.error('An error in the request occured.', error); + } + this.logger.warn( + 'eureka heartbeat FAILED, will retry.' + + `statusCode: ${response ? response.statusCode : 'unknown'}` + + `body: ${body} ${error | ''} ` + ); + } + }); + } + + /* + Sets up registry fetches on interval for the life of the application. + Registry fetch interval setting configuration property: eureka.registryFetchInterval + */ + startRegistryFetches() { + this.registryFetch = setInterval(() => { + this.fetchRegistry(err => { + if (err) this.logger.warn('Error fetching registry', err); + }); + }, this.config.eureka.registryFetchInterval); + } + + /* + Retrieves a list of instances from Eureka server given an appId + */ + getInstancesByAppId(appId) { + if (!appId) { + throw new RangeError('Unable to query instances with no appId'); + } + const instances = this.cache.app[appId.toUpperCase()] || []; + if (instances.length === 0) { + this.logger.warn(`Unable to retrieve instances for appId: ${appId}`); + } + return instances; + } + + /* + Retrieves a list of instances from Eureka server given a vipAddress + */ + getInstancesByVipAddress(vipAddress) { + if (!vipAddress) { + throw new RangeError('Unable to query instances with no vipAddress'); + } + const instances = this.cache.vip[vipAddress] || []; + if (instances.length === 0) { + this.logger.warn(`Unable to retrieves instances for vipAddress: ${vipAddress}`); + } + return instances; + } + + /* + Orchestrates fetching registry + */ + fetchRegistry(callback = noop) { + if (this.config.shouldUseDelta && this.hasFullRegistry) { + this.fetchDelta(callback); + } else { + this.fetchFullRegistry(callback); + } + } + + /* + Retrieves all applications registered with the Eureka server + */ + fetchFullRegistry(callback = noop) { + this.eurekaRequest({ + uri: '', + headers: { + Accept: 'application/json', + }, + }, (error, response, body) => { + if (!error && response.statusCode === 200) { + this.logger.debug('retrieved full registry successfully'); + try { + this.transformRegistry(JSON.parse(body)); + } catch (ex) { + return callback(ex); + } + this.emit('registryUpdated'); + this.hasFullRegistry = true; + return callback(null); + } else if (error) { + this.logger.warn('Error fetching registry', error); + return callback(error); + } + callback(new Error('Unable to retrieve full registry from Eureka server')); + }); + } + + /* + Retrieves all applications registered with the Eureka server + */ + fetchDelta(callback = noop) { + this.eurekaRequest({ + uri: 'delta', + headers: { + Accept: 'application/json', + }, + }, (error, response, body) => { + if (!error && response.statusCode === 200) { + this.logger.debug('retrieved delta successfully'); + let applications; + try { + const jsonBody = JSON.parse(body); + applications = jsonBody.applications.application; + this.handleDelta(this.cache, applications); + return callback(null); + } catch (ex) { + return callback(ex); + } + } else if (error) { + this.logger.warn('Error fetching delta registry', error); + return callback(error); + } + callback(new Error('Unable to retrieve delta registry from Eureka server')); + }); + } + /* + Transforms the given registry and caches the registry locally + */ + transformRegistry(registry) { + if (!registry) { + this.logger.warn('Unable to transform empty registry'); + } else { + if (!registry.applications.application) { + return; + } + const newCache = { app: {}, vip: {} }; + if (Array.isArray(registry.applications.application)) { + registry.applications.application.forEach((app) => { + this.transformApp(app, newCache); + }); + } else { + this.transformApp(registry.applications.application, newCache); + } + this.cache = newCache; + } + } + + /* + Transforms the given application and places in client cache. If an application + has a single instance, the instance is placed into the cache as an array of one + */ + transformApp(app, cache) { + if (app.instance.length) { + app.instance + .filter(this.validateInstance.bind(this)) + .forEach((inst) => this.addInstance(cache, inst)); + } else if (this.validateInstance(app.instance)) { + this.addInstance(cache, app.instance); + } + } + + /* + Returns true if instance filtering is disabled, or if the instance is UP + */ + validateInstance(instance) { + return (!this.config.eureka.filterUpInstances || instance.status === 'UP'); + } + + /* + Returns an array of vipAddresses from string vipAddress given by eureka + */ + splitVipAddress(vipAddress) { // eslint-disable-line + if (typeof vipAddress !== 'string') { + return []; + } + + return vipAddress.split(','); + } + + handleDelta(cache, appDelta) { + const delta = normalizeDelta(appDelta); + delta.forEach((app) => { + app.instance.forEach((instance) => { + switch (instance.actionType) { + case 'ADDED': this.addInstance(cache, instance); break; + case 'MODIFIED': this.modifyInstance(cache, instance); break; + case 'DELETED': this.deleteInstance(cache, instance); break; + default: this.logger.warn('Unknown delta actionType', instance.actionType); break; + } + }); + }); + } + + addInstance(cache, instance) { + if (!this.validateInstance(instance)) return; + const vipAddresses = this.splitVipAddress(instance.vipAddress); + const appName = instance.app.toUpperCase(); + vipAddresses.forEach((vipAddress) => { + const alreadyContains = findIndex(cache.vip[vipAddress], findInstance(instance)) > -1; + if (alreadyContains) return; + if (!cache.vip[vipAddress]) { + cache.vip[vipAddress] = []; + } + cache.vip[vipAddress].push(instance); + }); + if (!cache.app[appName]) cache.app[appName] = []; + const alreadyContains = findIndex(cache.app[appName], findInstance(instance)) > -1; + if (alreadyContains) return; + cache.app[appName].push(instance); + } + + modifyInstance(cache, instance) { + const vipAddresses = this.splitVipAddress(instance.vipAddress); + const appName = instance.app.toUpperCase(); + vipAddresses.forEach((vipAddress) => { + const index = findIndex(cache.vip[vipAddress], findInstance(instance)); + if (index > -1) cache.vip[vipAddress].splice(index, 1, instance); + else this.addInstance(cache, instance); + }); + const index = findIndex(cache.app[appName], findInstance(instance)); + if (index > -1) cache.app[appName].splice(cache.vip[instance.vipAddress], 1, instance); + else this.addInstance(cache, instance); + } + + deleteInstance(cache, instance) { + const vipAddresses = this.splitVipAddress(instance.vipAddress); + const appName = instance.app.toUpperCase(); + vipAddresses.forEach((vipAddress) => { + const index = findIndex(cache.vip[vipAddress], findInstance(instance)); + if (index > -1) cache.vip[vipAddress].splice(index, 1); + }); + const index = findIndex(cache.app[appName], findInstance(instance)); + if (index > -1) cache.app[appName].splice(cache.vip[instance.vipAddress], 1); + } + + /* + Fetches the metadata using the built-in client and updates the instance + configuration with the hostname and IP address. If the value of the config + option 'eureka.useLocalMetadata' is true, then the local IP address and + hostname is used. Otherwise, the public IP address and hostname is used. If + 'eureka.preferIpAddress' is true, the IP address will be used as the hostname. + + A string replacement is done on the healthCheckUrl, statusPageUrl and + homePageUrl so that users can define the URLs with a placeholder for the + host ('__HOST__'). This allows flexibility since the host isn't known until + the metadata is fetched. The replaced value respects the config option + 'eureka.useLocalMetadata' as described above. + + This will only get called when dataCenterInfo.name is Amazon, but you can + set config.eureka.fetchMetadata to false if you want to provide your own + metadata in AWS environments. + */ + addInstanceMetadata(callback = noop) { + this.metadataClient.fetchMetadata(metadataResult => { + this.config.instance.dataCenterInfo.metadata = merge( + this.config.instance.dataCenterInfo.metadata, + metadataResult + ); + const useLocal = this.config.eureka.useLocalMetadata; + const preferIpAddress = this.config.eureka.preferIpAddress; + const metadataHostName = metadataResult[useLocal ? 'local-hostname' : 'public-hostname']; + const metadataIpAddress = metadataResult[useLocal ? 'local-ipv4' : 'public-ipv4']; + this.config.instance.hostName = preferIpAddress ? metadataIpAddress : metadataHostName; + this.config.instance.ipAddr = metadataIpAddress; + + if (this.config.instance.statusPageUrl) { + const { statusPageUrl } = this.config.instance; + const replacedUrl = statusPageUrl.replace('__HOST__', this.config.instance.hostName); + this.config.instance.statusPageUrl = replacedUrl; + } + if (this.config.instance.healthCheckUrl) { + const { healthCheckUrl } = this.config.instance; + const replacedUrl = healthCheckUrl.replace('__HOST__', this.config.instance.hostName); + this.config.instance.healthCheckUrl = replacedUrl; + } + if (this.config.instance.homePageUrl) { + const { homePageUrl } = this.config.instance; + const replacedUrl = homePageUrl.replace('__HOST__', this.config.instance.hostName); + this.config.instance.homePageUrl = replacedUrl; + } + + callback(); + }); + } + + /* + Helper method for making a request to the Eureka server. Handles resolving + the current cluster as well as some default options. + */ + eurekaRequest(opts, callback, retryAttempt = 0) { + waterfall([ + /* + Resolve Eureka Clusters + */ + done => { + this.clusterResolver.resolveEurekaUrl((err, eurekaUrl) => { + if (err) return done(err); + const requestOpts = merge({}, opts, { + baseUrl: eurekaUrl, + gzip: true, + }); + done(null, requestOpts); + }, retryAttempt); + }, + /* + Apply Request Middleware + */ + (requestOpts, done) => { + this.requestMiddleware(requestOpts, (newRequestOpts) => { + if (typeof newRequestOpts !== 'object') { + return done(new Error('requestMiddleware did not return an object')); + } + done(null, newRequestOpts); + }); + }, + /* + Perform Request + */ + (requestOpts, done) => { + const method = requestOpts.method ? requestOpts.method.toUpperCase() : 'GET'; + const url = new URL(requestOpts.baseUrl + requestOpts.uri); + + const headers = requestOpts.headers || {}; + headers['Content-Type'] = 'application/json'; + + const options = { + method, + hostname: url.hostname, + port: url.port, + path: url.pathname, + headers, + cert: requestOpts.cert, + key: requestOpts.key, + ca: requestOpts.ca, + }; + this.logger.debug(`prepared options for the request ${JSON.stringify(options)}`); + + let response = {}; + const req = https.request(options, (res) => { + this.logger.debug(`Received status code: ${res.statusCode}`); + + response = res; + let data = ''; + if (res.statusCode === 204) { + done(null, res, null, requestOpts); + } else { + res.on('data', chunk => { + data += chunk; + }); + res.on('end', () => { + this.logger.debug(`Received data: ${data}`); + done(null, res, data, requestOpts); + }); + } + }); + req.on('error', e => { + this.logger.error(`Error occurred on ${url}: ${e}`); + done(e, response, null, requestOpts); + }); + if (requestOpts.body) { + req.write(JSON.stringify(requestOpts.body)); + } + req.end(); + }, + ], + /* + Handle Final Output. + */ + (error, response, body, requestOpts) => { + if (error) this.logger.error('Problem making eureka request', error); + + // Perform retry if request failed and we have attempts left + const responseInvalid = response + && response.statusCode + && String(response.statusCode)[0] === '5'; + + if ((error || responseInvalid) && retryAttempt < this.config.eureka.maxRetries) { + const nextRetryDelay = this.config.eureka.requestRetryDelay * (retryAttempt + 1); + this.logger.warn(`Eureka request failed to endpoint ${requestOpts.baseUrl}, ` + + `next server retry in ${nextRetryDelay}ms`); + + setTimeout(() => this.eurekaRequest(opts, callback, retryAttempt + 1), + nextRetryDelay); + return; + } + + callback(error, response, body); + }); + } +} diff --git a/onboarding-enabler-nodejs/src/Logger.js b/onboarding-enabler-nodejs/src/Logger.js new file mode 100644 index 0000000000..455342c687 --- /dev/null +++ b/onboarding-enabler-nodejs/src/Logger.js @@ -0,0 +1,81 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable no-underscore-dangle */ +const LEVELS = { + error: 50, + warn: 40, + info: 30, + debug: 20, +}; +const DEFAULT_LEVEL = LEVELS.info; + +export default class Logger { + constructor() { + this._level = DEFAULT_LEVEL; + } + + level(inVal) { + let val = inVal; + if (val) { + if (typeof val === 'string') { + val = LEVELS[val]; + } + this._level = val || DEFAULT_LEVEL; + } + return this._level; + } + + // Abstract the console call: + _log(method, args) { + if (this._level <= LEVELS[method === 'log' ? 'debug' : method]) { + /* eslint-disable no-console */ + console[method](...args); + /* eslint-enable no-console */ + } + } + + error(...args) { + return this._log('error', args); + } + warn(...args) { + return this._log('warn', args); + } + info(...args) { + return this._log('info', args); + } + debug(...args) { + return this._log('log', args); + } +} diff --git a/onboarding-enabler-nodejs/src/defaultConfig.js b/onboarding-enabler-nodejs/src/defaultConfig.js new file mode 100644 index 0000000000..b448838749 --- /dev/null +++ b/onboarding-enabler-nodejs/src/defaultConfig.js @@ -0,0 +1,57 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Default configuration values: +export default { + requestMiddleware: (request, done) => done(request), + shouldUseDelta: false, + eureka: { + heartbeatInterval: 30000, + registryFetchInterval: 30000, + maxRetries: 3, + requestRetryDelay: 500, + fetchRegistry: true, + filterUpInstances: true, + servicePath: '/eureka/v2/apps/', + ssl: false, + useDns: false, + preferSameZone: true, + clusterRefreshInterval: 300000, + fetchMetadata: true, + registerWithEureka: true, + useLocalMetadata: false, + preferIpAddress: false, + }, + instance: {}, +}; diff --git a/onboarding-enabler-nodejs/src/deltaUtils.js b/onboarding-enabler-nodejs/src/deltaUtils.js new file mode 100644 index 0000000000..8ed4443525 --- /dev/null +++ b/onboarding-enabler-nodejs/src/deltaUtils.js @@ -0,0 +1,51 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + General utilities for handling processing of delta changes from eureka. +*/ +export function arrayOrObj(mysteryValue) { + return Array.isArray(mysteryValue) ? mysteryValue : [mysteryValue]; +} + +export function findInstance(a) { + return b => a.hostName === b.hostName && a.port.$ === b.port.$; +} + +export function normalizeDelta(appDelta) { + return arrayOrObj(appDelta).map((app) => { + app.instance = arrayOrObj(app.instance); + return app; + }); +} diff --git a/onboarding-enabler-nodejs/src/index.js b/onboarding-enabler-nodejs/src/index.js index df8a04d2d0..a1a12f9d01 100644 --- a/onboarding-enabler-nodejs/src/index.js +++ b/onboarding-enabler-nodejs/src/index.js @@ -8,9 +8,9 @@ * Copyright Contributors to the Zowe Project. */ -const Eureka = require('eureka-js-client').Eureka; -const yaml = require('js-yaml'); -const fs = require('fs'); +import Eureka from './EurekaClient.js'; +import yaml from 'js-yaml'; +import * as fs from 'fs'; let certFile = null; let keyFile = null; @@ -21,56 +21,48 @@ let passPhrase = null; * Read ssl service configuration */ function readTlsProps() { - try { - const config = yaml.load(fs.readFileSync('config/service-configuration.yml', 'utf8')); - certFile = config.ssl.certificate; - keyFile = config.ssl.keystore; - caFile = config.ssl.caFile; - passPhrase = config.ssl.keyPassword; - - } catch (e) { - console.log(e); - } + try { + const config = yaml.load(fs.readFileSync('config/service-configuration.yml', 'utf8')); + certFile = config.ssl.certificate; + keyFile = config.ssl.keystore; + caFile = config.ssl.caFile; + passPhrase = config.ssl.keyPassword; + } catch (e) { + console.log(e); + } } readTlsProps(); -let tlsOptions = { - cert: fs.readFileSync(certFile), - key: fs.readFileSync(keyFile), - passphrase: passPhrase, - ca: fs.readFileSync(caFile) +export const tlsOptions = { + cert: fs.readFileSync(certFile), + key: fs.readFileSync(keyFile), + passphrase: passPhrase, + ca: fs.readFileSync(caFile), }; const client = new Eureka({ - filename: 'service-configuration', - cwd: 'config/', - requestMiddleware: (requestOpts, done) => { - done(Object.assign(requestOpts, tlsOptions)); - } + filename: 'service-configuration', + cwd: 'config/', + requestMiddleware: (requestOpts, done) => { + done(Object.assign(requestOpts, tlsOptions)); + }, }); /** * Function that uses the eureka-js-client library to register the application to Eureka */ -function connectToEureka() { - client.start(function(error) { - if (error != null) { - console.log(JSON.stringify(error)); - } - }); +export function connectToEureka() { + client.start((error) => { + if (error != null) { + console.log(JSON.stringify(error)); + } + }); } /** * Unregister the Eureka client from Eureka (i.e. when the application down) */ -function unregisterFromEureka() { - console.log("\nUnregistering the service from Eureka...") - client.stop(); +export function unregisterFromEureka() { + console.log('\nUnregistering the service from Eureka...'); + client.stop(); } - -connectToEureka(); - -module.exports = {connectToEureka, tlsOptions, unregisterFromEureka}; - - - diff --git a/onboarding-enabler-nodejs/test/AwsMetadata.test.js b/onboarding-enabler-nodejs/test/AwsMetadata.test.js new file mode 100644 index 0000000000..1b86accc42 --- /dev/null +++ b/onboarding-enabler-nodejs/test/AwsMetadata.test.js @@ -0,0 +1,180 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import sinon from 'sinon'; +import * as chai from 'chai'; +import sinonChai from 'sinon-chai'; +import AwsMetadata from '../src/AwsMetadata.js'; + +const expect = chai.expect; + +chai.use(sinonChai); + +function mockResponses(type) { + const requestStub = sinon.stub(global, 'fetch'); + const mock = (url, body) => { + requestStub.withArgs(url).returns(Promise.resolve({ + ok: true, + statusCode: 200, + text: () => Promise.resolve(body), + json: () => Promise.resolve(JSON.parse(body)), + })); + }; + const mockError = (url) => { + requestStub.withArgs(url).returns(Promise.resolve({ + ok: false, + statusMessage: 'fail', + statusCode: 500, + text: () => Promise.resolve(null), + json: () => Promise.resolve(null), + })); + }; + mock('http://127.0.0.1:8888/latest/meta-data/ami-id', 'ami-123'); + mock('http://127.0.0.1:8888/latest/meta-data/instance-id', 'i123'); + mock('http://127.0.0.1:8888/latest/meta-data/instance-type', 'medium'); + mock('http://127.0.0.1:8888/latest/meta-data/local-ipv4', '1.1.1.1'); + mock('http://127.0.0.1:8888/latest/meta-data/local-hostname', 'ip-127-0-0-1'); + mock('http://127.0.0.1:8888/latest/meta-data/placement/availability-zone', 'fake-1'); + switch (type) { + case 'full': + mock('http://127.0.0.1:8888/latest/meta-data/public-hostname', 'ec2-127-0-0-1'); + mock('http://127.0.0.1:8888/latest/meta-data/public-ipv4', '2.2.2.2'); + mock('http://127.0.0.1:8888/latest/dynamic/instance-identity/document', '{"accountId":"123456"}'); + break; + case 'withoutPublic': + mock('http://127.0.0.1:8888/latest/meta-data/public-hostname', undefined); + mock('http://127.0.0.1:8888/latest/meta-data/public-ipv4', null); + mock('http://127.0.0.1:8888/latest/dynamic/instance-identity/document', '{"accountId":"123456"}'); + break; + case 'failing': + mockError('http://127.0.0.1:8888/latest/meta-data/public-hostname', undefined); + mockError('http://127.0.0.1:8888/latest/meta-data/public-ipv4', null); + mockError('http://127.0.0.1:8888/latest/dynamic/instance-identity/document', '{"accountId":"123456"}'); + break; + default: + } + mock('http://127.0.0.1:8888/latest/meta-data/mac', 'AB:CD:EF:GH:IJ'); + mock('http://127.0.0.1:8888/latest/meta-data/network/interfaces/macs/AB:CD:EF:GH:IJ/vpc-id', 'vpc123'); + return requestStub; +} + +describe('AWS Metadata client', () => { + describe('fetchMetadata()', () => { + let client; + beforeEach(() => { + client = new AwsMetadata({ host: '127.0.0.1:8888' }); + }); + + it('should call metadata URIs', (done) => { + const requestStub = mockResponses('full'); + const expected = { + accountId: '123456', + 'ami-id': 'ami-123', + 'availability-zone': 'fake-1', + 'instance-id': 'i123', + 'instance-type': 'medium', + 'local-hostname': 'ip-127-0-0-1', + 'local-ipv4': '1.1.1.1', + mac: 'AB:CD:EF:GH:IJ', + 'public-hostname': 'ec2-127-0-0-1', + 'public-ipv4': '2.2.2.2', + 'vpc-id': 'vpc123', + }; + + client.fetchMetadata(data => { + try { + expect(data).to.deep.equal(expected); + done(); + } catch (e) { + done(e); + } finally { + requestStub.restore(); + } + }); + }); + + it('should call metadata URIs and filter out null and undefined values', (done) => { + const requestStub = mockResponses('withoutPublic'); + + const expected = { + accountId: '123456', + 'ami-id': 'ami-123', + 'availability-zone': 'fake-1', + 'instance-id': 'i123', + 'instance-type': 'medium', + 'local-hostname': 'ip-127-0-0-1', + 'local-ipv4': '1.1.1.1', + mac: 'AB:CD:EF:GH:IJ', + 'vpc-id': 'vpc123', + }; + + client.fetchMetadata(data => { + try { + expect(data).to.deep.equal(expected); + done(); + } catch (e) { + done(e); + } finally { + requestStub.restore(); + } + }); + }); + + it('should call metadata URIs and filter out errored values', (done) => { + const requestStub = mockResponses('failing'); + + const expected = { + 'ami-id': 'ami-123', + 'availability-zone': 'fake-1', + 'instance-id': 'i123', + 'instance-type': 'medium', + 'local-hostname': 'ip-127-0-0-1', + 'local-ipv4': '1.1.1.1', + mac: 'AB:CD:EF:GH:IJ', + 'vpc-id': 'vpc123', + }; + + client.fetchMetadata(data => { + try { + expect(data).to.deep.equal(expected); + done(); + } catch (e) { + done(e); + } finally { + requestStub.restore(); + } + }); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/ConfigClusterResolver.test.js b/onboarding-enabler-nodejs/test/ConfigClusterResolver.test.js new file mode 100644 index 0000000000..ec9d310123 --- /dev/null +++ b/onboarding-enabler-nodejs/test/ConfigClusterResolver.test.js @@ -0,0 +1,220 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable no-unused-expressions */ +import { expect } from 'chai'; +import merge from 'lodash/merge.js'; + +import ConfigClusterResolver from '../src/ConfigClusterResolver.js'; + +function makeConfig(overrides = {}) { + const config = { + instance: { + dataCenterInfo: { metadata: { 'availability-zone': '1b' } }, + }, + eureka: { + maxRetries: 0, + ec2Region: 'my-region', + }, + }; + return merge({}, config, overrides); +} + +describe('Config Cluster Resolver', () => { + describe('resolveEurekaUrl() with host/port config', () => { + let resolver; + beforeEach(() => { + resolver = new ConfigClusterResolver(makeConfig({ + eureka: { + host: 'eureka.mydomain.com', + servicePath: '/eureka/v2/apps/', + port: 9999, + }, + })); + }); + + it('should return base Eureka URL using configured host', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://eureka.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + }); + + describe('resolveEurekaUrl() with default serviceUrls', () => { + let resolver; + beforeEach(() => { + resolver = new ConfigClusterResolver(makeConfig({ + eureka: { + serviceUrls: { + default: [ + 'http://eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + }, + }, + })); + }); + + it('should return first Eureka URL from configured serviceUrls', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://eureka1.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + + it('should return next Eureka URL from configured serviceUrls', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://eureka2.mydomain.com:9999/eureka/v2/apps/'); + // next attempt should still be the next server + resolver.resolveEurekaUrl((errTwo, eurekaUrlTwo) => { + expect(eurekaUrlTwo).to.equal('http://eureka2.mydomain.com:9999/eureka/v2/apps/'); + }); + }, 1); + }); + }); + + describe('resolveEurekaUrl() with zoned serviceUrls', () => { + let resolver; + beforeEach(() => { + resolver = new ConfigClusterResolver(makeConfig({ + eureka: { + availabilityZones: { + 'my-region': ['1a', '1b', '1c'], + }, + serviceUrls: { + '1a': [ + 'http://1a-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1b': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1c': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + }, + }, + })); + }); + + it('should return first Eureka URL from configured serviceUrls', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://1a-eureka1.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + }); + + describe('resolveEurekaUrl() with zoned serviceUrls and preferSameZone', () => { + let resolver; + beforeEach(() => { + resolver = new ConfigClusterResolver(makeConfig({ + eureka: { + preferSameZone: true, + availabilityZones: { + 'my-region': ['1a', '1b', '1c'], + }, + serviceUrls: { + '1a': [ + 'http://1a-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1b': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1c': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + }, + }, + })); + }); + + it('should return first Eureka URL from configured serviceUrls', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + }); + + describe('resolveEurekaUrl(), zoned serviceUrls, preferSameZone, missing dataCenterInfo', () => { + let resolver; + const config = { + instance: {}, + eureka: { + maxRetries: 0, + ec2Region: 'my-region', + preferSameZone: true, + availabilityZones: { + 'my-region': ['1a', '1b', '1c'], + }, + serviceUrls: { + '1a': [ + 'http://1a-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1a-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1b': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + '1c': [ + 'http://1b-eureka1.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka2.mydomain.com:9999/eureka/v2/apps/', + 'http://1b-eureka3.mydomain.com:9999/eureka/v2/apps/', + ], + }, + }, + }; + beforeEach(() => { + resolver = new ConfigClusterResolver(config); + }); + + it('should return first Eureka URL from configured serviceUrls', () => { + resolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://1a-eureka1.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/DnsClusterResolver.test.js b/onboarding-enabler-nodejs/test/DnsClusterResolver.test.js new file mode 100644 index 0000000000..6f98773959 --- /dev/null +++ b/onboarding-enabler-nodejs/test/DnsClusterResolver.test.js @@ -0,0 +1,358 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable no-unused-expressions */ +import sinon from 'sinon'; +import dns from 'dns'; +import merge from 'lodash/merge.js'; + +import DnsClusterResolver from '../src/DnsClusterResolver.js'; +import * as chai from 'chai'; +const expect = chai.expect; +import sinonChai from 'sinon-chai'; + +chai.use(sinonChai); + +function makeConfig(overrides = {}) { + const config = { + instance: { + dataCenterInfo: { metadata: { 'availability-zone': '1b' } }, + }, + eureka: { + host: 'eureka.mydomain.com', + servicePath: '/eureka/v2/apps/', + port: 9999, + maxRetries: 0, + ec2Region: 'my-region', + }, + }; + return merge({}, config, overrides); +} + +describe('DNS Cluster Resolver', () => { + describe('DnsClusterResolver', () => { + it('should throw error when ec2Region is undefined', () => { + const config = makeConfig(); + config.eureka.ec2Region = undefined; + function fn() { + return new DnsClusterResolver(config); + } + expect(fn).to.throw(); + }); + }); + + describe('startClusterRefresh()', () => { + let dnsResolver; + let refreshStub; + let clock; + beforeEach(() => { + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + dnsResolver.refreshCurrentCluster.restore(); + clock.restore(); + }); + + it('should start cluster refreshes on interval', () => { + dnsResolver = new DnsClusterResolver(makeConfig({ + eureka: { clusterRefreshInterval: 300000 }, + })); + refreshStub = sinon.stub(dnsResolver, 'refreshCurrentCluster'); + clock.tick(300000); + expect(refreshStub).to.have.been.calledOnce; + clock.tick(300000); + expect(refreshStub).to.have.been.calledTwice; + clock.restore(); + }); + + it('should log warning on refresh failure', () => { + dnsResolver = new DnsClusterResolver(makeConfig({ + eureka: { clusterRefreshInterval: 300000 }, + })); + refreshStub = sinon.stub(dnsResolver, 'refreshCurrentCluster'); + refreshStub.yields(new Error('fail')); + clock.tick(300000); + expect(refreshStub).to.have.been.calledOnce; + clock.tick(300000); + expect(refreshStub).to.have.been.calledTwice; + clock.restore(); + }); + }); + + describe('resolveEurekaUrl()', () => { + let dnsResolver; + beforeEach(() => { + dnsResolver = new DnsClusterResolver(makeConfig()); + }); + + afterEach(() => { + dnsResolver.resolveClusterHosts.restore(); + }); + + it('should return base Eureka URL using current cluster host', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.yields(null, ['a.mydomain.com', 'b.mydomain.com', 'c.mydomain.com']); + dnsResolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://a.mydomain.com:9999/eureka/v2/apps/'); + }); + }); + + it('should return base Eureka URL using next cluster host on retry', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.yields(null, ['a.mydomain.com', 'b.mydomain.com', 'c.mydomain.com']); + dnsResolver.resolveEurekaUrl((err, eurekaUrl) => { + expect(eurekaUrl).to.equal('http://b.mydomain.com:9999/eureka/v2/apps/'); + expect(dnsResolver.serverList).to.eql(['b.mydomain.com', 'c.mydomain.com', + 'a.mydomain.com']); + }, 1); + }); + + it('should return error when resolve fails', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.yields(new Error('fail')); + dnsResolver.resolveEurekaUrl((err) => { + expect(err).to.not.equal(undefined); + expect(err.message).to.equal('fail'); + }); + }); + }); + + describe('getCurrentCluster()', () => { + let dnsResolver; + beforeEach(() => { + dnsResolver = new DnsClusterResolver(makeConfig()); + }); + + afterEach(() => { + dnsResolver.resolveClusterHosts.restore(); + }); + + it('should call cluster refresh if server list is undefined', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.onCall(0).yields(null, ['a', 'b', 'c']); + resolveHostsStub.onCall(1).yields(null, ['f', 'a', 'c']); + dnsResolver.getCurrentCluster((err, serverList) => { + expect(serverList).to.include.members(['a', 'b', 'c']); + dnsResolver.getCurrentCluster((errTwo, serverListTwo) => { + expect(serverListTwo).to.include.members(['a', 'b', 'c']); + }); + }); + }); + + it('should return error when refresh fails', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.yields(new Error('fail')); + dnsResolver.getCurrentCluster((err) => { + expect(err).to.not.equal(undefined); + expect(err.message).to.equal('fail'); + }); + }); + }); + + describe('refreshCurrentCluster', () => { + let dnsResolver; + beforeEach(() => { + dnsResolver = new DnsClusterResolver(makeConfig()); + }); + + afterEach(() => { + dnsResolver.resolveClusterHosts.restore(); + }); + + it('should refresh server list', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.onCall(0).yields(null, ['a', 'b', 'c']); + resolveHostsStub.onCall(1).yields(null, ['a', 'b', 'c', 'd']); + dnsResolver.refreshCurrentCluster((err) => { + expect(err).to.equal(undefined); + expect(dnsResolver.serverList).to.eql(['a', 'b', 'c']); + dnsResolver.refreshCurrentCluster((errTwo) => { + expect(errTwo).to.equal(undefined); + expect(dnsResolver.serverList).to.eql(['a', 'b', 'c', 'd']); + }); + }); + }); + + it('should maintain server list when cluster remains unchanged', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.onCall(0).yields(null, ['a', 'b', 'c']); + resolveHostsStub.onCall(1).yields(null, ['c', 'a', 'b']); + dnsResolver.refreshCurrentCluster((err) => { + expect(err).to.equal(undefined); + expect(dnsResolver.serverList).to.eql(['a', 'b', 'c']); + dnsResolver.refreshCurrentCluster((errTwo) => { + expect(errTwo).to.equal(undefined); + expect(dnsResolver.serverList).to.eql(['a', 'b', 'c']); + }); + }); + }); + + it('should return error when resolve fails', () => { + const resolveHostsStub = sinon.stub(dnsResolver, 'resolveClusterHosts'); + resolveHostsStub.yields(new Error('fail')); + dnsResolver.refreshCurrentCluster((err) => { + expect(err).to.not.equal(undefined); + expect(err.message).to.equal('fail'); + }); + }); + }); + + describe('resolveClusterHosts()', () => { + const eurekaHosts = [ + '1a.eureka.mydomain.com', + '1b.eureka.mydomain.com', + '1c.eureka.mydomain.com', + ]; + + afterEach(() => { + dns.resolveTxt.restore(); + }); + + it('should resolve hosts using DNS', (done) => { + const dnsResolver = new DnsClusterResolver(makeConfig()); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com').yields(null, [eurekaHosts]); + resolveStub.withArgs('txt.1a.eureka.mydomain.com').yields(null, [['1.2.3.4']]); + resolveStub.withArgs('txt.1b.eureka.mydomain.com').yields(null, [['2.2.3.4']]); + resolveStub.withArgs('txt.1c.eureka.mydomain.com').yields(null, [['3.2.3.4']]); + dnsResolver.resolveClusterHosts((err, hosts) => { + expect(hosts).to.include.members(['1.2.3.4', '2.2.3.4', '3.2.3.4']); + done(); + }); + }); + + it('should resolve hosts using DNS and zone affinity', (done) => { + const dnsResolver = new DnsClusterResolver(makeConfig({ + eureka: { preferSameZone: true }, + })); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com').yields(null, [eurekaHosts]); + resolveStub.withArgs('txt.1a.eureka.mydomain.com').yields(null, [['1.2.3.4']]); + resolveStub.withArgs('txt.1b.eureka.mydomain.com').yields(null, [['2.2.3.4']]); + resolveStub.withArgs('txt.1c.eureka.mydomain.com').yields(null, [['3.2.3.4']]); + dnsResolver.resolveClusterHosts((err, hosts) => { + expect(hosts[0]).to.equal('2.2.3.4'); + expect(hosts).to.include.members(['1.2.3.4', '2.2.3.4', '3.2.3.4']); + dnsResolver.resolveClusterHosts((error, hostsTwo) => { + expect(hostsTwo[0]).to.equal('2.2.3.4'); + expect(hostsTwo).to.include.members(['1.2.3.4', '2.2.3.4', '3.2.3.4']); + done(); + }); + }); + }); + + it('should resolve hosts when dataCenterInfo is undefined', (done) => { + const config = { + instance: {}, + eureka: { + preferSameZone: true, + host: 'eureka.mydomain.com', + servicePath: '/eureka/v2/apps/', + port: 9999, + maxRetries: 0, + ec2Region: 'my-region', + }, + }; + const dnsResolver = new DnsClusterResolver(config); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com').yields(null, [eurekaHosts]); + resolveStub.withArgs('txt.1a.eureka.mydomain.com').yields(null, [['1.2.3.4']]); + resolveStub.withArgs('txt.1b.eureka.mydomain.com').yields(null, [['2.2.3.4']]); + resolveStub.withArgs('txt.1c.eureka.mydomain.com').yields(null, [['3.2.3.4']]); + dnsResolver.resolveClusterHosts((err, hosts) => { + expect(hosts).to.include.members(['1.2.3.4', '2.2.3.4', '3.2.3.4']); + dnsResolver.resolveClusterHosts((error, hostsTwo) => { + expect(hostsTwo).to.include.members(['1.2.3.4', '2.2.3.4', '3.2.3.4']); + done(); + }); + }); + }); + + it('should return error when initial DNS lookup fails', () => { + const resolveCb = sinon.spy(); + const dnsResolver = new DnsClusterResolver(makeConfig()); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com') + .yields(new Error('dns error'), null); + + function shouldNotThrow() { + dnsResolver.resolveClusterHosts(resolveCb); + } + + expect(shouldNotThrow).to.not.throw(); + expect(dns.resolveTxt).to.have.been.calledWithMatch('txt.my-region.eureka.mydomain.com'); + expect(resolveCb).to.have.been.calledWithMatch({ + message: 'Error resolving eureka cluster ' + + 'for region [my-region] using DNS: [Error: dns error]', + }); + }); + + it('should return error when DNS lookup fails for an individual zone', () => { + const resolveCb = sinon.spy(); + const dnsResolver = new DnsClusterResolver(makeConfig({ + eureka: { host: 'eureka.mydomain.com', port: 9999, ec2Region: 'my-region' }, + })); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com').yields(null, [eurekaHosts]); + resolveStub.withArgs('txt.1a.eureka.mydomain.com').yields(null, [['1.2.3.4']]); + resolveStub.withArgs('txt.1b.eureka.mydomain.com').yields(new Error('dns error'), null); + resolveStub.withArgs('txt.1c.eureka.mydomain.com').yields(null, [['3.2.3.4']]); + + function shouldNotThrow() { + dnsResolver.resolveClusterHosts(resolveCb); + } + + expect(shouldNotThrow).to.not.throw(); + expect(resolveCb).to.have.been.calledWithMatch({ + message: 'Error resolving cluster zone txt.1b.eureka.mydomain.com: [Error: dns error]', + }); + }); + + it('should return error when no hosts were found', (done) => { + const dnsResolver = new DnsClusterResolver(makeConfig()); + const resolveStub = sinon.stub(dns, 'resolveTxt'); + resolveStub.withArgs('txt.my-region.eureka.mydomain.com').yields(null, [eurekaHosts]); + resolveStub.withArgs('txt.1a.eureka.mydomain.com').yields(null, []); + resolveStub.withArgs('txt.1b.eureka.mydomain.com').yields(null, []); + resolveStub.withArgs('txt.1c.eureka.mydomain.com').yields(null, []); + dnsResolver.resolveClusterHosts((err) => { + expect(err).to.not.equal(undefined); + expect(err.message).to.equal('Unable to locate any Eureka hosts in any ' + + 'zone via DNS @ txt.my-region.eureka.mydomain.com'); + done(); + }); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/EurekaClient.test.js b/onboarding-enabler-nodejs/test/EurekaClient.test.js new file mode 100644 index 0000000000..73e6e6e39e --- /dev/null +++ b/onboarding-enabler-nodejs/test/EurekaClient.test.js @@ -0,0 +1,1407 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable no-unused-expressions, max-len */ +import sinon from 'sinon'; +import * as chai from 'chai'; +const expect = chai.expect; +import sinonChai from 'sinon-chai'; +import { EventEmitter } from 'events'; +import { join } from 'path'; +import merge from 'lodash/merge.js'; +import https from 'https'; + +import Eureka from '../src/EurekaClient.js'; +import DnsClusterResolver from '../src/DnsClusterResolver.js'; + +chai.use(sinonChai); + +function makeConfig(overrides = {}) { + const config = { + instance: { + app: 'app', + vipAddress: '1.2.2.3', + hostName: 'myhost', + port: 9999, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { host: '127.0.0.1', port: 9999, maxRetries: 0 }, + }; + return merge({}, config, overrides); +} + +function mockSuccessfulResponse(accumulator, statusCode) { + const res = { + statusCode: statusCode || 204, + callback: [], + on: (event, callback) => { + console.log(`EVENT ${event}`); + res.callback[event] = callback; + }, + }; + return sinon.stub(https, 'request').yields(res).returns({ + end: () => { + if (statusCode === 200 && res.callback.data('{}')); + if (res.callback.end) res.callback.end.apply(); + }, + write: (body) => { + if (accumulator) accumulator.body = body; + }, + on: () => {}, + }); +} + +describe('Eureka client', () => { + describe('Eureka()', () => { + it('should extend EventEmitter', () => { + expect(new Eureka(makeConfig())).to.be.instanceof(EventEmitter); + }); + + it('should throw an error if no config is found', () => { + function fn() { + return new Eureka(); + } + expect(fn).to.throw(); + }); + + it('should construct with the correct configuration values', () => { + function shouldThrow() { + return new Eureka(); + } + + function noApp() { + return new Eureka({ + instance: { + vipAddress: true, + port: true, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { + host: true, + port: true, + }, + }); + } + + function shouldWork() { + return new Eureka({ + instance: { + app: true, + vipAddress: true, + port: true, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { + host: true, + port: true, + }, + }); + } + + function shouldWorkNoInstance() { + return new Eureka({ + eureka: { + registerWithEureka: false, + host: true, + port: true, + }, + }); + } + + expect(shouldThrow).to.throw(); + expect(noApp).to.throw(/app/); + expect(shouldWork).to.not.throw(); + expect(shouldWorkNoInstance).to.not.throw(); + }); + + it('should use DnsClusterResolver when configured', () => { + const client = new Eureka({ + instance: { + app: true, + vipAddress: true, + port: true, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { + host: true, + port: true, + useDns: true, + ec2Region: 'my-region', + }, + }); + expect(client.clusterResolver.constructor).to.equal(DnsClusterResolver); + }); + + it('should throw when configured to useDns without setting ec2Region', () => { + function shouldThrow() { + return new Eureka({ + instance: { + app: true, + vipAddress: true, + port: true, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { + host: true, + port: true, + useDns: true, + }, + }); + } + expect(shouldThrow).to.throw(/ec2Region/); + }); + + it('should accept requestMiddleware', () => { + const requestMiddleware = (opts) => opts; + const client = new Eureka({ + requestMiddleware, + instance: { + app: true, + vipAddress: true, + port: true, + dataCenterInfo: { + name: 'MyOwn', + }, + }, + eureka: { + host: true, + port: true, + useDns: true, + ec2Region: 'my-region', + }, + }); + expect(client.requestMiddleware).to.equal(requestMiddleware); + }); + }); + + describe('get instanceId()', () => { + it('should return the configured instance id', () => { + const instanceId = 'test_id'; + const config = makeConfig({ + instance: { + instanceId, + }, + }); + const client = new Eureka(config); + expect(client.instanceId).to.equal(instanceId); + }); + + it('should return hostname for non-AWS datacenters', () => { + const config = makeConfig(); + const client = new Eureka(config); + expect(client.instanceId).to.equal('myhost'); + }); + + it('should return instance ID for AWS datacenters', () => { + const config = makeConfig({ + instance: { dataCenterInfo: { name: 'Amazon', metadata: { 'instance-id': 'i123' } } }, + }); + const client = new Eureka(config); + expect(client.instanceId).to.equal('i123'); + }); + }); + + describe('start()', () => { + let config; + let client; + let registerSpy; + let fetchRegistrySpy; + let heartbeatsSpy; + let registryFetchSpy; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + afterEach(() => { + registerSpy.restore(); + fetchRegistrySpy.restore(); + heartbeatsSpy.restore(); + registryFetchSpy.restore(); + }); + + it('should call register, fetch registry, startHeartbeat and startRegistryFetches', (done) => { + registerSpy = sinon.stub(client, 'register').callsArg(0); + fetchRegistrySpy = sinon.stub(client, 'fetchRegistry').callsArg(0); + heartbeatsSpy = sinon.stub(client, 'startHeartbeats'); + registryFetchSpy = sinon.stub(client, 'startRegistryFetches'); + const eventSpy = sinon.spy(); + client.on('started', eventSpy); + + client.start(() => { + expect(registerSpy).to.have.been.calledOnce; + expect(fetchRegistrySpy).to.have.been.calledOnce; + expect(heartbeatsSpy).to.have.been.calledOnce; + expect(registryFetchSpy).to.have.been.calledOnce; + expect(eventSpy).to.have.been.calledOnce; + done(); + }); + }); + + it('should call fetch registry and startRegistryFetches when registration disabled', (done) => { + config = makeConfig({ + eureka: { + registerWithEureka: false, + }, + }); + client = new Eureka(config); + + registerSpy = sinon.stub(client, 'register').callsArg(0); + fetchRegistrySpy = sinon.stub(client, 'fetchRegistry').callsArg(0); + heartbeatsSpy = sinon.stub(client, 'startHeartbeats'); + registryFetchSpy = sinon.stub(client, 'startRegistryFetches'); + const eventSpy = sinon.spy(); + client.on('started', eventSpy); + + client.start(() => { + expect(registerSpy).to.not.have.been.called; + expect(fetchRegistrySpy).to.have.been.calledOnce; + expect(heartbeatsSpy).to.not.have.been.called; + expect(registryFetchSpy).to.have.been.calledOnce; + expect(eventSpy).to.have.been.calledOnce; + done(); + }); + }); + + it('should return error on start failure', (done) => { + registerSpy = sinon.stub(client, 'register').yields(new Error('fail')); + fetchRegistrySpy = sinon.stub(client, 'fetchRegistry').callsArg(0); + heartbeatsSpy = sinon.stub(client, 'startHeartbeats'); + registryFetchSpy = sinon.stub(client, 'startRegistryFetches'); + const eventSpy = sinon.spy(); + client.on('started', eventSpy); + + client.start((error) => { + expect(error).to.match(/fail/); + expect(eventSpy).to.not.have.been.called; + done(); + }); + }); + }); + + describe('startHeartbeats()', () => { + let config; + let client; + let renewSpy; + let clock; + before(() => { + config = makeConfig(); + client = new Eureka(config); + renewSpy = sinon.stub(client, 'renew'); + clock = sinon.useFakeTimers(); + }); + + after(() => { + renewSpy.restore(); + clock.restore(); + }); + + it('should call renew on interval', () => { + client.startHeartbeats(); + clock.tick(30000); + expect(renewSpy).to.have.been.calledOnce; + clock.tick(30000); + expect(renewSpy).to.have.been.calledTwice; + }); + }); + + describe('startRegistryFetches()', () => { + let config; + let client; + let fetchRegistrySpy; + let clock; + before(() => { + config = makeConfig(); + client = new Eureka(config); + fetchRegistrySpy = sinon.stub(client, 'fetchRegistry'); + clock = sinon.useFakeTimers(); + }); + + after(() => { + fetchRegistrySpy.restore(); + clock.restore(); + }); + + it('should call renew on interval', () => { + client.startRegistryFetches(); + clock.tick(30000); + expect(fetchRegistrySpy).to.have.been.calledOnce; + clock.tick(30000); + expect(fetchRegistrySpy).to.have.been.calledTwice; + }); + }); + + describe('stop()', () => { + let config; + let client; + let deregisterSpy; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + deregisterSpy = sinon.stub(client, 'deregister').callsArg(0); + }); + + afterEach(() => { + deregisterSpy.restore(); + }); + + it('should call deregister', () => { + const stopCb = sinon.spy(); + client.stop(stopCb); + + expect(deregisterSpy).to.have.been.calledOnce; + expect(stopCb).to.have.been.calledOnce; + }); + + it('should skip deregister if registration disabled', () => { + config = makeConfig({ + eureka: { + registerWithEureka: false, + }, + }); + client = new Eureka(config); + + const stopCb = sinon.spy(); + client.stop(stopCb); + + expect(deregisterSpy).to.not.have.been.called; + expect(stopCb).to.have.been.calledOnce; + }); + }); + + describe('register()', () => { + let config; + let client; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + it('should trigger register event', (done) => { + const requestStub = mockSuccessfulResponse(); + client.on('registered', () => { + requestStub.restore(); + done(); + }); + client.register(); + }); + + it('should call register URI', () => { + const accumulator = {}; + const requestStub = mockSuccessfulResponse(accumulator); + client.register(); + expect(JSON.parse(accumulator.body)).to.deep.equal({ + instance: { + app: 'app', + hostName: 'myhost', + dataCenterInfo: { name: 'MyOwn' }, + port: 9999, + status: 'UP', + vipAddress: '1.2.2.3', + }, + }); + requestStub.restore(); + }); + + it('should throw error for non-204 response', () => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').yields({ + on: () => {}, + statusCode: 500, + }).returns({ + on: (type, callback) => { callbacks[type] = callback; }, + end: () => { callbacks.error.apply(); }, + write: () => {}, + }); + + const registerCb = sinon.spy(); + client.register(registerCb); + + expect(registerCb).to.have.been.calledWithMatch({ + message: 'eureka registration FAILED: status: 500 body: null', + }); + requestStub.restore(); + }); + + it('should throw error for request error', () => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').returns({ + on: (type, callback) => { callbacks[type] = callback; }, + write: () => {}, + end: () => {}, + }); + const registerCb = sinon.spy(); + client.register(registerCb); + callbacks.error(new Error('request error')); + + expect(registerCb).to.have.been.calledWithMatch({ message: 'request error' }); + requestStub.restore(); + }); + }); + + describe('deregister()', () => { + let config; + let client; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + it('should should trigger deregister event', () => { + const requestStub = mockSuccessfulResponse(); + + const eventSpy = sinon.spy(); + client.on('deregistered', eventSpy); + client.register(); + client.deregister(); + + requestStub.restore(); + }); + + it('should call deregister URI', () => { + const requestStub = mockSuccessfulResponse(); + client.deregister(); + + const options = requestStub.resolvesArg(0).args[0][0]; + expect(options.method).to.be.equal('DELETE'); + expect(options.hostname).to.be.equal('127.0.0.1'); + expect(options.port).to.be.equal('9999'); + expect(options.path).to.be.equal('/eureka/v2/apps/app/myhost'); + + requestStub.restore(); + }); + + it('should throw error for non-200 response', () => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').yields({ + on: () => {}, + statusCode: 500, + }).returns({ + on: (type, callback) => { callbacks[type] = callback; }, + end: () => { callbacks.error.apply(); }, + write: () => {}, + }); + + const deregisterCb = sinon.spy(); + client.deregister(deregisterCb); + + expect(deregisterCb).to.have.been.calledWithMatch({ + message: 'eureka deregistration FAILED: status: 500 body: null', + }); + requestStub.restore(); + }); + + it('should throw error for request error', () => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').returns({ + on: (type, callback) => { callbacks[type] = callback; }, + write: () => {}, + end: () => {}, + }); + const deregisterCb = sinon.spy(); + client.deregister(deregisterCb); + callbacks.error(new Error('request error')); + + expect(deregisterCb).to.have.been.calledWithMatch({ message: 'request error' }); + requestStub.restore(); + }); + }); + + describe('renew()', () => { + let config; + let client; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + it('should call heartbeat URI', () => { + const requestStub = mockSuccessfulResponse(); + client.renew(); + + const options = requestStub.resolvesArg(0).args[0][0]; + expect(options.method).to.be.equal('PUT'); + expect(options.hostname).to.be.equal('127.0.0.1'); + expect(options.port).to.be.equal('9999'); + expect(options.path).to.be.equal('/eureka/v2/apps/app/myhost'); + + requestStub.restore(); + }); + + it('should trigger a heartbeat event', (done) => { + const requestStub = mockSuccessfulResponse({}, 200); + client.on('heartbeat', () => { + requestStub.restore(); + done(); + }); + client.renew(); + }); + + it('should re-register on 404', (done) => { + const requestStub = sinon.stub(https, 'request'); + + client.on('registered', () => { + const postOptions = requestStub.resolvesArg(0).args[1][0]; + expect(postOptions.method).to.be.equal('POST'); + expect(postOptions.hostname).to.be.equal('127.0.0.1'); + expect(postOptions.port).to.be.equal('9999'); + expect(postOptions.path).to.be.equal('/eureka/v2/apps/app'); + + const putOptions = requestStub.resolvesArg(0).args[0][0]; + expect(putOptions.method).to.be.equal('PUT'); + expect(putOptions.hostname).to.be.equal('127.0.0.1'); + expect(putOptions.port).to.be.equal('9999'); + expect(putOptions.path).to.be.equal('/eureka/v2/apps/app/myhost'); + + requestStub.restore(); + done(); + }); + + const callbacks = []; + const req = { + end: () => {}, + write: () => {}, + on: (type, callback) => { + if (!callbacks[type]) callbacks[type] = callback; + }, + }; + requestStub.yields({ + statusCode: 404, + on: (type, callback) => { + if (!callbacks[type]) callbacks[type] = callback; + }, + }).returns(req); + + client.renew(); + + requestStub.yields({ + statusCode: 204, + on: () => {}, + }).returns(req); + callbacks.end.apply(); + }); + }); + + describe('eureka-client.yml', () => { + let stub; + let original; + before(() => { + original = `${process.cwd()}/test`; + stub = sinon.stub(process, 'cwd').returns(original); + }); + + after(() => { + stub.restore(); + }); + + it('should load the correct', () => { + const client = new Eureka(makeConfig()); + expect(client.config.eureka.custom).to.equal('test'); + }); + + it('should load the environment overrides', () => { + const client = new Eureka(makeConfig()); + expect(client.config.eureka.otherCustom).to.equal('test2'); + expect(client.config.eureka.overrides).to.equal(2); + }); + + it('should support a `cwd` and `filename` property', () => { + const client = new Eureka(makeConfig({ + cwd: join(original, 'fixtures'), + filename: 'config', + })); + expect(client.config.eureka.fromFixture).to.equal(true); + }); + + it('should throw error on malformed config file', () => { + function malformed() { + return new Eureka(makeConfig({ + cwd: join(__dirname, 'fixtures'), + filename: 'malformed-config', + })); + } + expect(malformed).to.throw(Error); + }); + it('should not throw error on malformed config file', () => { + function missingFile() { + return new Eureka(makeConfig({ + cwd: join(original, 'fixtures'), + filename: 'missing-config', + })); + } + expect(missingFile).to.not.throw(); + }); + }); + + describe('validateConfig()', () => { + let config; + beforeEach(() => { + config = makeConfig({ + instance: { dataCenterInfo: { name: 'Amazon' } }, + }); + }); + + it('should throw an exception with a missing instance.app', () => { + function badConfig() { + delete config.instance.app; + return new Eureka(config); + } + expect(badConfig).to.throw(TypeError); + }); + + it('should throw an exception with a missing instance.vipAddress', () => { + function badConfig() { + delete config.instance.vipAddress; + return new Eureka(config); + } + expect(badConfig).to.throw(TypeError); + }); + + it('should throw an exception with a missing instance.port', () => { + function badConfig() { + delete config.instance.port; + return new Eureka(config); + } + expect(badConfig).to.throw(TypeError); + }); + + it('should throw an exception with a missing instance.dataCenterInfo', () => { + function badConfig() { + delete config.instance.dataCenterInfo; + return new Eureka(config); + } + expect(badConfig).to.throw(TypeError); + }); + + it('should throw an exception with an invalid request middleware', () => { + function badConfig() { + config.requestMiddleware = 'invalid middleware'; + return new Eureka(config); + } + expect(badConfig).to.throw(TypeError); + }); + }); + + describe('getInstancesByAppId()', () => { + let client; + let config; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + it('should throw an exception if no appId is provided', () => { + function noAppId() { + client.getInstancesByAppId(); + } + expect(noAppId).to.throw(Error); + }); + + it('should return a list of instances if appId is registered', () => { + const appId = 'THESERVICENAME'; + const expectedInstances = [{ host: '127.0.0.1' }]; + client.cache.app[appId] = expectedInstances; + const actualInstances = client.getInstancesByAppId(appId); + expect(actualInstances).to.equal(expectedInstances); + }); + + it('should return empty array if no instances were found for given appId', () => { + expect(client.getInstancesByAppId('THESERVICENAME')).to.deep.equal([]); + }); + }); + + describe('getInstancesByVipAddress()', () => { + let client; + let config; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + }); + + it('should throw an exception if no vipAddress is provided', () => { + function noVipAddress() { + client.getInstancesByVipAddress(); + } + expect(noVipAddress).to.throw(Error); + }); + + it('should return a list of instances if vipAddress is registered', () => { + const vipAddress = 'the.vip.address'; + const expectedInstances = [{ host: '127.0.0.1' }]; + client.cache.vip[vipAddress] = expectedInstances; + const actualInstances = client.getInstancesByVipAddress(vipAddress); + expect(actualInstances).to.equal(expectedInstances); + }); + + it('should return empty array if no instances were found for given vipAddress', () => { + expect(client.getInstancesByVipAddress('the.vip.address')).to.deep.equal([]); + }); + }); + + describe('fetchRegistry()', () => { + let config; + let client; + beforeEach(() => { + config = makeConfig(); + client = new Eureka(config); + sinon.stub(client, 'transformRegistry'); + sinon.stub(client, 'handleDelta'); + }); + + afterEach(() => { + client.transformRegistry.restore(); + client.handleDelta.restore(); + }); + + it('should should trigger registryUpdated event', (done) => { + const requestStub = mockSuccessfulResponse({}, 200); + client.on('registryUpdated', () => { + requestStub.restore(); + done(); + }); + client.fetchRegistry(); + }); + + it('should call registry URI', (done) => { + const requestStub = mockSuccessfulResponse({}, 200); + + client.fetchRegistry(() => { + const options = requestStub.resolvesArg(0).args[0][0]; + expect(options.method).to.be.equal('GET'); + expect(options.hostname).to.be.equal('127.0.0.1'); + expect(options.port).to.be.equal('9999'); + expect(options.path).to.be.equal('/eureka/v2/apps/'); + requestStub.restore(); + done(); + }); + }); + + it('should call registry URI for delta', (done) => { + const requestStub = mockSuccessfulResponse(); + client.config.shouldUseDelta = true; + client.hasFullRegistry = true; + client.fetchRegistry(() => { + const options = requestStub.resolvesArg(0).args[0][0]; + expect(options.method).to.be.equal('GET'); + expect(options.hostname).to.be.equal('127.0.0.1'); + expect(options.port).to.be.equal('9999'); + expect(options.path).to.be.equal('/eureka/v2/apps/delta'); + requestStub.restore(); + done(); + }); + }); + + it('should throw error for non-200 response', (done) => { + const requestStub = mockSuccessfulResponse({}, 500); + client.fetchRegistry((msg) => { + expect(msg.message).to.be.equal('Unable to retrieve full registry from Eureka server'); + requestStub.restore(); + done(); + }); + }); + + it('should throw error for non-200 response for delta', (done) => { + const requestStub = mockSuccessfulResponse({}, 500); + client.config.shouldUseDelta = true; + client.hasFullRegistry = true; + client.fetchRegistry((msg) => { + expect(msg.message).to.be.equal('Unable to retrieve delta registry from Eureka server'); + requestStub.restore(); + done(); + }); + }); + + it('should throw error for request error', (done) => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').returns({ + on: (type, callback) => { callbacks[type] = callback; }, + write: () => {}, + end: () => {}, + }); + client.fetchRegistry((msg) => { + expect(msg.message).to.be.equal('request error'); + requestStub.restore(); + done(); + }); + callbacks.error(new Error('request error')); + }); + + it('should throw error for request error for delta request', (done) => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').returns({ + on: (type, callback) => { callbacks[type] = callback; }, + write: () => {}, + end: () => {}, + }); + client.config.shouldUseDelta = true; + client.hasFullRegistry = true; + client.fetchRegistry((msg) => { + expect(msg.message).to.be.equal('request error'); + requestStub.restore(); + done(); + }); + callbacks.error(new Error('request error')); + }); + + it('should throw error on invalid JSON', (done) => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').yields({ + statusCode: 200, + on: (type, callback) => { callbacks[type] = callback; }, + }).returns({ + on: () => {}, + end: () => { + callbacks.data('{ blah'); + callbacks.end.apply(); + }, + }); + + client.fetchRegistry(error => { + expect(error instanceof SyntaxError).to.be.true; + requestStub.restore(); + done(); + }); + }); + + it('should throw error on invalid JSON for delta request', (done) => { + const callbacks = []; + const requestStub = sinon.stub(https, 'request').yields({ + statusCode: 200, + on: (type, callback) => { callbacks[type] = callback; }, + }).returns({ + on: () => {}, + end: () => { + callbacks.data('{ blah'); + callbacks.end.apply(); + }, + }); + + client.config.shouldUseDelta = true; + client.hasFullRegistry = true; + client.fetchRegistry(error => { + expect(error instanceof SyntaxError).to.be.true; + requestStub.restore(); + done(); + }); + }); + }); + + describe('transformRegistry()', () => { + let client; + let config; + let registry; + let instance1; + let instance2; + let instance3; + let instance4; + let instance5; + let app1; + let app2; + let app3; + beforeEach(() => { + config = makeConfig(); + registry = { + applications: { application: {} }, + }; + instance1 = { hostName: '127.0.0.1', port: { $: 1000 }, app: 'theapp', vipAddress: 'vip1', status: 'UP' }; + instance2 = { hostName: '127.0.0.2', port: { $: 2000 }, app: 'theapptwo', vipAddress: 'vip2', status: 'UP' }; + instance3 = { hostName: '127.0.0.3', port: { $: 2000 }, app: 'theapp', vipAddress: 'vip2', status: 'UP' }; + instance4 = { hostName: '127.0.0.4', port: { $: 2000 }, app: 'theappthree', vipAddress: 'vip3', status: 'UP' }; + instance5 = { hostName: '127.0.0.5', port: { $: 2000 }, app: 'theappthree', vipAddress: 'vip2', status: 'UP' }; + + app1 = { name: 'theapp', instance: instance1 }; + app2 = { name: 'theapptwo', instance: [instance2, instance3] }; + app3 = { name: 'theappthree', instance: [instance5, instance4] }; + client = new Eureka(config); + }); + + it('should noop if empty registry', () => { + client.transformRegistry(undefined); + expect(client.cache.vip).to.be.empty; + expect(client.cache.app).to.be.empty; + }); + + it('should return clear the cache if no applications exist', () => { + registry.applications.application = null; + client.transformRegistry(registry); + expect(client.cache.vip).to.be.empty; + expect(client.cache.app).to.be.empty; + }); + + it('should transform a registry with one app', () => { + registry.applications.application = app1; + client.transformRegistry(registry); + expect(client.cache.app[app1.name.toUpperCase()].length).to.equal(1); + expect(client.cache.vip[instance1.vipAddress].length).to.equal(1); + }); + + it('should transform a registry with two or more apps', () => { + registry.applications.application = [app1, app2]; + client.transformRegistry(registry); + expect(client.cache.app[app1.name.toUpperCase()].length).to.equal(2); + expect(client.cache.vip[instance2.vipAddress].length).to.equal(2); + }); + + it('should transform a registry with a single application with multiple vips', () => { + registry.applications.application = [app3]; + client.transformRegistry(registry); + expect(client.cache.app[app3.name.toUpperCase()].length).to.equal(2); + expect(client.cache.vip[instance5.vipAddress].length).to.equal(1); + expect(client.cache.vip[instance4.vipAddress].length).to.equal(1); + }); + }); + + describe('transformApp()', () => { + let client; + let config; + let app; + let instance1; + let instance2; + let instance3; + let instance4; + let downInstance; + let theVip; + let multiVip; + let cache; + beforeEach(() => { + config = makeConfig({ + instance: { dataCenterInfo: { name: 'Amazon' } }, + }); + client = new Eureka(config); + theVip = 'theVip'; + multiVip = 'fooVip,barVip'; + instance1 = { hostName: '127.0.0.1', port: 1000, vipAddress: theVip, app: 'theapp', status: 'UP' }; + instance2 = { hostName: '127.0.0.2', port: 2000, vipAddress: theVip, app: 'theapp', status: 'UP' }; + instance3 = { hostName: '127.0.0.5', port: 2000, vipAddress: multiVip, app: 'theapp', status: 'UP' }; + instance4 = { hostName: '127.0.0.6', port: 2000, vipAddress: void 0, app: 'theapp', status: 'UP' }; + downInstance = { hostName: '127.0.0.7', port: 2000, app: 'theapp', vipAddress: theVip, status: 'DOWN' }; + app = { name: 'theapp' }; + cache = { app: {}, vip: {} }; + }); + + it('should transform an app with one instance', () => { + app.instance = instance1; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(1); + expect(cache.vip[theVip].length).to.equal(1); + }); + + it('should transform an app with one instance that has a comma separated vipAddress', () => { + app.instance = instance3; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(1); + expect(cache.vip[multiVip.split(',')[0]].length).to.equal(1); + expect(cache.vip[multiVip.split(',')[1]].length).to.equal(1); + }); + + it('should transform an app with one instance that has no vipAddress', () => { + app.instance = instance4; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(1); + expect(Object.keys(cache.vip).length).to.equal(0); + }); + + it('should transform an app with two or more instances', () => { + app.instance = [instance1, instance2, instance3]; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(3); + expect(cache.vip[theVip].length).to.equal(2); + expect(cache.vip[multiVip.split(',')[0]].length).to.equal(1); + expect(cache.vip[multiVip.split(',')[1]].length).to.equal(1); + }); + + it('should filter UP instances by default', () => { + app.instance = [instance1, instance2, downInstance]; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(2); + expect(cache.vip[theVip].length).to.equal(2); + }); + + it('should not filter UP instances when filterUpInstances === false', () => { + config = makeConfig({ + instance: { dataCenterInfo: { name: 'Amazon' } }, + eureka: { filterUpInstances: false }, + }); + client = new Eureka(config); + app.instance = [instance1, instance2, downInstance]; + client.transformApp(app, cache); + expect(cache.app[app.name.toUpperCase()].length).to.equal(3); + expect(cache.vip[theVip].length).to.equal(3); + }); + }); + + describe('addInstanceMetadata()', () => { + let client; + let config; + let instanceConfig; + let awsMetadata; + let metadataSpy; + beforeEach(() => { + instanceConfig = { + app: 'app', + vipAddress: '1.2.3.4', + port: 9999, + dataCenterInfo: { name: 'Amazon' }, + statusPageUrl: 'http://__HOST__:8080/info', + healthCheckUrl: 'http://__HOST__:8077/healthcheck', + homePageUrl: 'http://__HOST__:8080/', + }; + awsMetadata = { + 'public-hostname': 'ec2-127-0-0-1.us-fake-1.mydomain.com', + 'public-ipv4': '54.54.54.54', + 'local-hostname': 'fake-1', + 'local-ipv4': '10.0.1.1', + }; + }); + + afterEach(() => { + client.metadataClient.fetchMetadata.restore(); + }); + + it('should update hosts with AWS metadata public host', () => { + // Setup + config = { + instance: instanceConfig, + eureka: { host: '127.0.0.1', port: 9999 }, + }; + client = new Eureka(config); + metadataSpy = sinon.spy(); + + sinon.stub(client.metadataClient, 'fetchMetadata').yields(awsMetadata); + + // Act + client.addInstanceMetadata(metadataSpy); + expect(client.config.instance.hostName).to.equal('ec2-127-0-0-1.us-fake-1.mydomain.com'); + expect(client.config.instance.ipAddr).to.equal('54.54.54.54'); + expect(client.config.instance.statusPageUrl).to.equal('http://ec2-127-0-0-1.us-fake-1.mydomain.com:8080/info'); + expect(client.config.instance.healthCheckUrl).to.equal('http://ec2-127-0-0-1.us-fake-1.mydomain.com:8077/healthcheck'); + expect(client.config.instance.homePageUrl).to.equal('http://ec2-127-0-0-1.us-fake-1.mydomain.com:8080/'); + }); + + it('should update hosts with AWS metadata public IP when preferIpAddress === true', () => { + // Setup + config = { + instance: instanceConfig, + eureka: { host: '127.0.0.1', port: 9999, preferIpAddress: true }, + }; + client = new Eureka(config); + metadataSpy = sinon.spy(); + + sinon.stub(client.metadataClient, 'fetchMetadata').yields(awsMetadata); + + // Act + client.addInstanceMetadata(metadataSpy); + expect(client.config.instance.hostName).to.equal('54.54.54.54'); + expect(client.config.instance.ipAddr).to.equal('54.54.54.54'); + expect(client.config.instance.statusPageUrl).to.equal('http://54.54.54.54:8080/info'); + expect(client.config.instance.healthCheckUrl).to.equal('http://54.54.54.54:8077/healthcheck'); + expect(client.config.instance.homePageUrl).to.equal('http://54.54.54.54:8080/'); + }); + + it('should update hosts with AWS metadata local host if useLocalMetadata === true', () => { + // Setup + config = { + instance: instanceConfig, + eureka: { host: '127.0.0.1', port: 9999, useLocalMetadata: true }, + }; + client = new Eureka(config); + metadataSpy = sinon.spy(); + + sinon.stub(client.metadataClient, 'fetchMetadata').yields(awsMetadata); + + // Act + client.addInstanceMetadata(metadataSpy); + expect(client.config.instance.hostName).to.equal('fake-1'); + expect(client.config.instance.ipAddr).to.equal('10.0.1.1'); + expect(client.config.instance.statusPageUrl).to.equal('http://fake-1:8080/info'); + expect(client.config.instance.healthCheckUrl).to.equal('http://fake-1:8077/healthcheck'); + expect(client.config.instance.homePageUrl).to.equal('http://fake-1:8080/'); + }); + + it('should update hosts with AWS metadata local IP if useLocalMetadata === true' + + ' and preferIpAddress === true', () => { + // Setup + config = { + instance: instanceConfig, + eureka: { host: '127.0.0.1', port: 9999, useLocalMetadata: true, preferIpAddress: true }, + }; + client = new Eureka(config); + metadataSpy = sinon.spy(); + + sinon.stub(client.metadataClient, 'fetchMetadata').yields(awsMetadata); + + // Act + client.addInstanceMetadata(metadataSpy); + expect(client.config.instance.hostName).to.equal('10.0.1.1'); + expect(client.config.instance.ipAddr).to.equal('10.0.1.1'); + expect(client.config.instance.statusPageUrl).to.equal('http://10.0.1.1:8080/info'); + expect(client.config.instance.healthCheckUrl).to.equal('http://10.0.1.1:8077/healthcheck'); + expect(client.config.instance.homePageUrl).to.equal('http://10.0.1.1:8080/'); + }); + }); + + describe('eurekaRequest()', () => { + it('should call requestMiddleware with request options', () => { + const overrides = { + requestMiddleware: sinon.spy((opts, done) => done(opts)), + }; + const requestStub = mockSuccessfulResponse({}, 200); + const config = makeConfig(overrides); + const client = new Eureka(config); + client.eurekaRequest({}, (error) => { + expect(Boolean(error)).to.equal(false); + expect(overrides.requestMiddleware).to.be.calledOnce; + expect(overrides.requestMiddleware.args[0][0]).to.be.an('object'); + }); + requestStub.restore(); + }); + it('should catch an error in requestMiddleware', () => { + const overrides = { + requestMiddleware: sinon.spy((opts, done) => { + done(); + }), + }; + const requestStub = mockSuccessfulResponse({}, 200); + const config = makeConfig(overrides); + const client = new Eureka(config); + client.eurekaRequest({}, (error) => { + expect(overrides.requestMiddleware).to.be.calledOnce; + expect(error).to.be.an('error'); + }); + requestStub.restore(); + }); + it('should check the returnType of requestMiddleware', () => { + const overrides = { + requestMiddleware: sinon.spy((opts, done) => done('foo')), + }; + const requestStub = mockSuccessfulResponse({}, 200); + const config = makeConfig(overrides); + const client = new Eureka(config); + client.eurekaRequest({}, (error) => { + expect(error).to.be.an('error'); + expect(error.message).to.equal('requestMiddleware did not return an object'); + }); + requestStub.restore(); + }); + + it('should retry next server on request failure', (done) => { + const overrides = { + eureka: { + serviceUrls: { + default: ['http://serverA', 'http://serverB'], + }, + maxRetries: 3, + requestRetryDelay: 0, + }, + }; + const config = makeConfig(overrides); + const client = new Eureka(config); + const callbacks = []; + const requestStub = sinon.stub(https, 'request'); + const req = { + write: () => {}, + on: (type, callback) => { + if (!callbacks[type]) callbacks[type] = []; + callbacks[type].push(callback); + }, + end: () => {}, + }; + requestStub.yields({ + statusCode: 500, + on: (type, callback) => { + callbacks[type] = [callback]; + }, + }).returns(req); + + client.eurekaRequest({ uri: '/path' }, (error) => { + expect(error).to.be.null; + expect(requestStub.args[0][0].hostname).to.be.equal('servera'); + expect(requestStub.args[1][0].hostname).to.be.equal('serverb'); + done(); + }); + + requestStub.yields({ + statusCode: 200, + on: (type, callback) => { + callbacks[type].push(callback); + req.end = callbacks.end[1]; + }, + }).returns(req); + callbacks.end[0].apply(); + }); + }); + + + describe('handleDelta()', () => { + let client; + beforeEach(() => { + const config = makeConfig({ shouldUseDelta: true }); + client = new Eureka(config); + }); + + it('should add instances', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'ADDED' }, + ], + }, + ]; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(1); + expect(client.cache.app.THEAPP).to.have.length(1); + }); + + it('should handle duplicate instances on add', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'ADDED' }, + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'ADDED' }, + ], + }, + ]; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(1); + expect(client.cache.app.THEAPP).to.have.length(1); + }); + + it('should modify instances', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'MODIFIED', newProp: 'foo' }, + ], + }, + ]; + const original = { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'MODIFIED' }; + client.cache = { + app: { THEAPP: [original] }, + vip: { thevip: [original] }, + }; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(1); + expect(client.cache.app.THEAPP).to.have.length(1); + expect(client.cache.vip.thevip[0]).to.have.property('newProp'); + expect(client.cache.app.THEAPP[0]).to.have.property('newProp'); + }); + + it('should modify instances even when status is not UP', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'DOWN', actionType: 'MODIFIED', newProp: 'foo' }, + ], + }, + ]; + const original = { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'MODIFIED' }; + client.cache = { + app: { THEAPP: [original] }, + vip: { thevip: [original] }, + }; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(1); + expect(client.cache.app.THEAPP).to.have.length(1); + expect(client.cache.vip.thevip[0]).to.have.property('newProp'); + expect(client.cache.app.THEAPP[0]).to.have.property('newProp'); + }); + + it('should add if instance doesnt exist when modifying', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'MODIFIED', newProp: 'foo' }, + ], + }, + ]; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(1); + expect(client.cache.app.THEAPP).to.have.length(1); + expect(client.cache.vip.thevip[0]).to.have.property('newProp'); + expect(client.cache.app.THEAPP[0]).to.have.property('newProp'); + }); + + it('should delete instances', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'DELETED', newProp: 'foo' }, + ], + }, + ]; + const original = { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'ADDED' }; + client.cache = { + app: { THEAPP: [original] }, + vip: { thevip: [original] }, + }; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(0); + expect(client.cache.app.THEAPP).to.have.length(0); + }); + + it('should not delete instances if they do not exist', () => { + const appDelta = [ + { + instance: [ + { hostName: '127.0.0.1', port: { $: 1000 }, app: 'THEAPP', vipAddress: 'thevip', status: 'UP', actionType: 'DELETED', newProp: 'foo' }, + ], + }, + ]; + client.cache = { + app: { THEAPP: [] }, + vip: { thevip: [] }, + }; + + client.handleDelta(client.cache, appDelta); + expect(client.cache.vip.thevip).to.have.length(0); + expect(client.cache.app.THEAPP).to.have.length(0); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/Logger.test.js b/onboarding-enabler-nodejs/test/Logger.test.js new file mode 100644 index 0000000000..eece6bdd67 --- /dev/null +++ b/onboarding-enabler-nodejs/test/Logger.test.js @@ -0,0 +1,123 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import sinon from 'sinon'; +import { expect } from 'chai'; +import Logger from '../src/Logger.js'; + +const DEFAULT_LEVEL = 30; + +describe('Logger', () => { + it('should construct with no args', () => { + expect(() => new Logger()).to.not.throw(); + }); + + describe('Logger Instance', () => { + let logger; + beforeEach(() => { + logger = new Logger(); + }); + + it('should return the current log level from the "level" method', () => { + expect(logger.level()).to.equal(DEFAULT_LEVEL); + }); + + it('should update the log level if passed a number', () => { + logger.level(100); + expect(logger.level()).to.equal(100); + logger.level(15); + expect(logger.level()).to.equal(15); + }); + + it('should update the log level if a valid string is passed', () => { + logger.level('warn'); + expect(logger.level()).to.equal(40); + logger.level('error'); + expect(logger.level()).to.equal(50); + }); + + it('should use the default log level is an invalid string is passed', () => { + logger.level('invalid'); + expect(logger.level()).to.equal(DEFAULT_LEVEL); + }); + + it('should only log a message if the log level is higher than the level', () => { + logger.level(100); + const stub = sinon.stub(console, 'error'); + logger.error('Some Error'); + expect(stub.callCount).to.equal(0); + logger.level(50); + logger.error('Other Error'); + expect(stub.callCount).to.equal(1); + stub.restore(); + }); + + describe('Log Methods', () => { + beforeEach(() => { + // Log everything: + logger.level(-1); + }); + + const stubConsole = method => sinon.stub(console, method); + + it('should call console.log with debug', () => { + const stub = stubConsole('log'); + logger.debug('test'); + expect(stub.callCount).to.equal(1); + stub.restore(); + }); + + it('should call console.info with info', () => { + const stub = stubConsole('info'); + logger.info('test'); + expect(stub.callCount).to.equal(1); + stub.restore(); + }); + + it('should call console.warn with warn', () => { + const stub = stubConsole('warn'); + logger.warn('test'); + expect(stub.callCount).to.equal(1); + stub.restore(); + }); + + it('should call console.error with error', () => { + const stub = stubConsole('error'); + logger.error('test'); + expect(stub.callCount).to.equal(1); + stub.restore(); + }); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/deltaUtil.test.js b/onboarding-enabler-nodejs/test/deltaUtil.test.js new file mode 100644 index 0000000000..4087a947ff --- /dev/null +++ b/onboarding-enabler-nodejs/test/deltaUtil.test.js @@ -0,0 +1,73 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { expect } from 'chai'; +import { arrayOrObj, findInstance, normalizeDelta } from '../src/deltaUtils.js'; + +describe('deltaUtils', () => { + describe('arrayOrObj', () => { + it('should return same array if passed an array', () => { + const arr = ['foo']; + expect(arrayOrObj(arr)).to.equal(arr); + }); + it('should return an array containing obj', () => { + const obj = {}; + expect(arrayOrObj(obj)[0]).to.equal(obj); + }); + }); + describe('findInstance', () => { + it('should return true if objects match', () => { + const obj1 = { hostName: 'foo', port: { $: '6969' } }; + const obj2 = { hostName: 'foo', port: { $: '6969' } }; + expect(findInstance(obj1)(obj2)).to.equal(true); + }); + it('should return false if objects do not match', () => { + const obj1 = { hostName: 'foo', port: { $: '6969' } }; + const obj2 = { hostName: 'bar', port: { $: '1111' } }; + expect(findInstance(obj1)(obj2)).to.equal(false); + }); + }); + describe('normalizeDelta', () => { + it('should normalize nested objs to arrays', () => { + const delta = { + instance: { + hostName: 'foo', port: { $: '6969' }, + }, + }; + const normalized = normalizeDelta(delta); + expect(normalized).to.be.an('array'); + expect(normalized[0].instance).to.be.an('array'); + }); + }); +}); diff --git a/onboarding-enabler-nodejs/test/eureka-client-test.yml b/onboarding-enabler-nodejs/test/eureka-client-test.yml new file mode 100644 index 0000000000..0a3bf6a45a --- /dev/null +++ b/onboarding-enabler-nodejs/test/eureka-client-test.yml @@ -0,0 +1,3 @@ +eureka: + overrides: 2 + otherCustom: 'test2' diff --git a/onboarding-enabler-nodejs/test/eureka-client.yml b/onboarding-enabler-nodejs/test/eureka-client.yml new file mode 100644 index 0000000000..d48dd85e1a --- /dev/null +++ b/onboarding-enabler-nodejs/test/eureka-client.yml @@ -0,0 +1,11 @@ +eureka: + overrides: 1 + custom: 'test' + heartbeatInterval: 999 + registryFetchInterval: 999 + fetchRegistry: false + servicePath: '/eureka/v2/apps/' + ssl: false + useDns: false + fetchMetadata: false +instance: {} diff --git a/onboarding-enabler-nodejs/test/fixtures/config.yml b/onboarding-enabler-nodejs/test/fixtures/config.yml new file mode 100644 index 0000000000..33991b729e --- /dev/null +++ b/onboarding-enabler-nodejs/test/fixtures/config.yml @@ -0,0 +1,2 @@ +eureka: + fromFixture: true diff --git a/onboarding-enabler-nodejs/test/fixtures/malformed-config.yml b/onboarding-enabler-nodejs/test/fixtures/malformed-config.yml new file mode 100644 index 0000000000..4cedf36b95 --- /dev/null +++ b/onboarding-enabler-nodejs/test/fixtures/malformed-config.yml @@ -0,0 +1,3 @@ +eureka: + fromFixture: true + @something: false diff --git a/onboarding-enabler-nodejs/test/integration.test.js b/onboarding-enabler-nodejs/test/integration.test.js new file mode 100644 index 0000000000..325f784f5e --- /dev/null +++ b/onboarding-enabler-nodejs/test/integration.test.js @@ -0,0 +1,102 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Jacob Quatier + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Eureka from '../src/EurekaClient.js'; +import { expect } from 'chai'; +import fs from 'fs'; + +describe('Integration Test', () => { + const config = { + instance: { + app: 'jqservice', + hostName: 'localhost', + ipAddr: '127.0.0.1', + port: { + $: 8080, + '@enabled': true, + }, + vipAddress: 'jq.test.something.com', + instanceId: 'localhost:hwexpress:8080', + dataCenterInfo: { + '@class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo', + name: 'MyOwn', + }, + }, + eureka: { + heartbeatInterval: 30000, + registryFetchInterval: 5000, + fetchRegistry: true, + waitForRegistry: true, + servicePath: '/eureka/v2/apps/', + ssl: true, + useDns: false, + fetchMetadata: true, + host: 'localhost', + port: 10011, + }, + ssl: { + certificate: '../keystore/localhost/localhost.keystore.cer', + keystore: '../keystore/localhost/localhost.keystore.key', + caFile: '../keystore/localhost/localhost.pem', + keyPassword: 'password', + }, + requestMiddleware: (requestOpts, done) => { + done(Object.assign(requestOpts, { + cert: fs.readFileSync(config.ssl.certificate), + key: fs.readFileSync(config.ssl.keystore), + passphrase: config.ssl.keyPassword, + ca: fs.readFileSync(config.ssl.caFile), + })); + }, + }; + + const client = new Eureka(config); + before((done) => { + client.start(done); + }); + + it('should be able to get instance by the app id', () => { + const instances = client.getInstancesByAppId(config.instance.app); + expect(instances.length).to.equal(1); + }); + + it('should be able to get instance by the vipAddress', () => { + const instances = client.getInstancesByVipAddress(config.instance.vipAddress); + expect(instances.length).to.equal(1); + }); + + after((done) => { + client.stop(done); + }); +}); diff --git a/scripts/docs/.npmrc b/scripts/docs/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/scripts/docs/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/scripts/release_components/.npmrc b/scripts/release_components/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/scripts/release_components/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/scripts/release_docs/.npmrc b/scripts/release_docs/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/scripts/release_docs/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/zowe-cli-id-federation-plugin/.npmrc b/zowe-cli-id-federation-plugin/.npmrc index e69de29bb2..c06a38e8c8 100644 --- a/zowe-cli-id-federation-plugin/.npmrc +++ b/zowe-cli-id-federation-plugin/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/zss-sample-service/.npmrc b/zss-sample-service/.npmrc new file mode 100644 index 0000000000..c06a38e8c8 --- /dev/null +++ b/zss-sample-service/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +registry=https://zowe.jfrog.io/artifactory/api/npm/npm-org/ diff --git a/zss-sample-service/package.json b/zss-sample-service/package.json index 096df94e1f..8169caec21 100644 --- a/zss-sample-service/package.json +++ b/zss-sample-service/package.json @@ -6,6 +6,6 @@ "start": "node server.js" }, "dependencies": { - "express": "4.21.1" + "express": "4.21.2" } }