diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc3b1606..7245db7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: with: node-version: "20.x" - name: Install dependencies - run: npm install + run: npm ci - name: Lint run: npm run lint @@ -31,7 +31,9 @@ jobs: with: node-version: ${{ matrix.nodeVersion }} - name: Install dependencies - run: npm install + run: npm ci + - name: Build CLI + run: npm run build - name: Run tests run: npm run test @@ -45,12 +47,14 @@ jobs: nodeVersion: ["22.13.1", "24.14.1"] os: [windows-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.nodeVersion }} - name: Install dependencies - run: npm install + run: npm ci + - name: Build CLI + run: npm run build - name: Run tests run: npm run test @@ -71,6 +75,8 @@ jobs: - name: Install libsecret run: sudo apt-get install -y libsecret-1-0 - name: Install dependencies - run: npm install + run: npm ci + - name: Build CLI + run: npm run build - name: Run tests run: npm run test diff --git a/bin/run.js b/bin/run.js index b469ba4b..f0a7a73c 100755 --- a/bin/run.js +++ b/bin/run.js @@ -4,4 +4,5 @@ enableCompileCache(); import { execute, settings } from '@oclif/core'; settings.performanceEnabled = true; +settings.enableAutoTranspile = false; await execute({ dir: import.meta.url }); diff --git a/package-lock.json b/package-lock.json index 1abc4bb4..b8970997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,15 +39,18 @@ "uuid": "^13.0.0" }, "bin": { - "axway": "bin/run.js" + "axway": "bin/run" }, "devDependencies": { "@koa/router": "^14.0.0", "@oclif/test": "^4.1.14", + "@types/chai-as-promised": "^8.0.2", + "@types/jest": "^30.0.0", "@types/lodash": "^4.17.20", "@types/node": "^22", "@typescript-eslint/eslint-plugin": "^8.46.3", "@typescript-eslint/parser": "^8.59.3", + "c8": "^11.0.0", "caller-path": "^4.0.0", "chai": "6.2.0", "chai-as-promised": "^8.0.2", @@ -62,6 +65,7 @@ "mock-stdin": "^1.0.0", "mustache": "^4.2.0", "nock": "^14.0.10", + "testdouble": "^3.20.2", "tmp": "^0.2.5", "ts-node": "^10.9.2", "typescript": "^5.9.3" @@ -70,6 +74,41 @@ "node": ">=22.11.0" } }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -739,6 +778,125 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", + "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", + "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -987,6 +1145,13 @@ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", "license": "MIT" }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, "node_modules/@sindresorhus/is": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.1.1.tgz", @@ -999,6 +1164,55 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "deprecated": "Deprecated: no longer maintained and no longer used by Sinon packages. See\n https://github.com/sinonjs/nise/issues/243 for replacement details.", + "dev": true, + "license": "(Unlicense OR Apache-2.0)" + }, "node_modules/@stylistic/eslint-plugin": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.6.1.tgz", @@ -1073,6 +1287,34 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-meQ1wDr1K5KRCSvG2lX7n7/5wf70BeptTKst0axGvnN6zqaVpRqegoIbugiAPSqOW9K9aL8gDVrm7a2LXOtn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1086,6 +1328,44 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1117,6 +1397,47 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/sinon": { + "version": "10.0.20", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.20.tgz", + "integrity": "sha512-2APKKruFNCAZgx3daAyACGzWuJ028VVCUDk6o2rw/Z4PXT0ogwdV4KUegW0MwVs0Zu59auPXbbuBJHF12Sx1Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-15.0.1.tgz", + "integrity": "sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -1863,6 +2184,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -2054,6 +2385,40 @@ "node": ">= 0.8" } }, + "node_modules/c8": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz", + "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^8.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": "20 || >=22" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -2568,6 +2933,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookies": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz", @@ -3739,6 +4111,24 @@ "node": ">=6" } }, + "node_modules/expect": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.4.1", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -4400,6 +4790,13 @@ "he": "bin/he" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", @@ -4948,6 +5345,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -5124,39 +5531,308 @@ "dev": true, "license": "ISC" }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" } }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "license": "Apache-2.0", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" } }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-diff": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", + "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.4.1", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", + "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.4.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.4.1", + "picomatch": "^4.0.3", + "pretty-format": "30.4.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", + "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", + "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jose": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", @@ -5166,6 +5842,13 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -5219,6 +5902,13 @@ "json5": "lib/cli.js" } }, + "node_modules/just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true, + "license": "MIT" + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -5471,6 +6161,22 @@ "dev": true, "license": "ISC" }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -5567,11 +6273,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -5680,6 +6386,37 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, + "node_modules/nise": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, "node_modules/nock": { "version": "14.0.10", "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.10.tgz", @@ -6225,6 +6962,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/pretty-ms": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", @@ -6292,6 +7058,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/quibble": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.9.2.tgz", + "integrity": "sha512-BrL7hrZcbyyt5ZDfePkGFDc3m82uUtxCPOnpRUrkOdtBnmV9ldQKxXORkKL8eIzToRNaCpIPyKyfdfq/tBlFAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">= 0.14.0" + } + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -6367,6 +7147,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", + "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", + "dev": true, + "license": "MIT" + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6880,6 +7676,59 @@ "simple-concat": "^1.0.0" } }, + "node_modules/sinon": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", + "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", + "deprecated": "16.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6889,6 +7738,29 @@ "node": ">=0.10.0" } }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7051,6 +7923,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object-es5": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz", + "integrity": "sha512-vE7Xdx9ylG4JI16zy7/ObKUB+MtxuMcWlj/WHHr3+yAlQoN6sst2stU9E+2Qs3OrlJw/Pf3loWxL1GauEHf6MA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "is-plain-obj": "^1.0.0", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-object-es5/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", @@ -7183,6 +8079,128 @@ "node": ">=6" } }, + "node_modules/test-exclude": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^13.0.6", + "minimatch": "^10.2.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz", + "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/testdouble": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.20.2.tgz", + "integrity": "sha512-790e9vJKdfddWNOaxW1/V9FcMk48cPEl3eJSj2i8Hh1fX89qArEJ6cp3DBnaECpGXc3xKJVWbc1jeNlWYWgiMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "quibble": "^0.9.2", + "stringify-object-es5": "^2.5.0", + "theredoc": "^1.0.0" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/theredoc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", + "integrity": "sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -7374,6 +8392,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", @@ -7577,6 +8605,32 @@ "dev": true, "license": "MIT" }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index ff38e8d0..c0f8add2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "bugs": "https://github.com/appcelerator/amplify-tooling/issues", "repository": "https://github.com/appcelerator/amplify-tooling", "bin": { - "axway": "./bin/run.js" + "axway": "./bin/run" }, "scripts": { "debug": "node --inspect=9254 --enable-source-maps dist/index.js", @@ -22,7 +22,7 @@ "test": "sh -c 'mocha --exit --recursive -r test/helpers/setup.js --exclude \"test/helpers/**\" --slow 15000 --timeout 40000 \"${@:-test}\"' sh", "lint": "eslint . --ignore-pattern 'dist/**'", "watch": "tsc --watch", - "postinstall": "node dist/scripts/postinstall.js || node -e true" + "postinstall": "node -e \"const fs=require('fs'); if(fs.existsSync('dist/scripts/postinstall.js')) require('./dist/scripts/postinstall.js')\"" }, "dependencies": { "@inquirer/prompts": "^7.9.0", @@ -56,10 +56,13 @@ "devDependencies": { "@koa/router": "^14.0.0", "@oclif/test": "^4.1.14", + "@types/chai-as-promised": "^8.0.2", + "@types/jest": "^30.0.0", "@types/lodash": "^4.17.20", "@types/node": "^22", "@typescript-eslint/eslint-plugin": "^8.46.3", "@typescript-eslint/parser": "^8.59.3", + "c8": "^11.0.0", "caller-path": "^4.0.0", "chai": "6.2.0", "chai-as-promised": "^8.0.2", @@ -74,6 +77,7 @@ "mock-stdin": "^1.0.0", "mustache": "^4.2.0", "nock": "^14.0.10", + "testdouble": "^3.20.2", "tmp": "^0.2.5", "ts-node": "^10.9.2", "typescript": "^5.9.3" diff --git a/src/commands/team/index.ts b/src/commands/team/index.ts index c8ee2c65..e24c8331 100644 --- a/src/commands/team/index.ts +++ b/src/commands/team/index.ts @@ -7,7 +7,7 @@ export default class TeamCommand extends Command { static override summary = 'Manage Amplify Platform organization teams.'; static override description = `You must be authenticated to view or manage organization teams. -Run ${highlight(`"<%= config.bin %> auth login"`) } to authenticate. +Run ${highlight('"<%= config.bin %> auth login"')} to authenticate. You may specify the team by name or guid. diff --git a/src/commands/team/user/add.ts b/src/commands/team/user/add.ts index 813e8529..f9ed16a5 100644 --- a/src/commands/team/user/add.ts +++ b/src/commands/team/user/add.ts @@ -13,7 +13,7 @@ export default class TeamUserAdd extends Command { A team user must be assigned a platform role and optionally a product specific role. You may specify the roles with multiple --role "role" options or a single --role "role1,role2,role3" option with a comma-separated list of roles. -To view available team user roles, run: ${highlight(`"<%= config.bin %> team user roles"`)}`; +To view available team user roles, run: ${highlight('"<%= config.bin %> team user roles"')}`; static override args = { team: Args.string({ diff --git a/src/commands/team/user/index.ts b/src/commands/team/user/index.ts index 3ad74c1b..d08378ef 100644 --- a/src/commands/team/user/index.ts +++ b/src/commands/team/user/index.ts @@ -7,7 +7,7 @@ export default class TeamUserCommand extends Command { static override summary = 'Manage team users.'; - static override description = `You may specify the team by name or guid, user by email address or guid, or service account by guid or client id.`; + static override description = 'You may specify the team by name or guid, user by email address or guid, or service account by guid or client id.'; static override examples = [ { diff --git a/src/lib/config.ts b/src/lib/config.ts index 0ce1af09..f76c39f2 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -228,7 +228,7 @@ export class Config { } let arr = this.get(key, [], true); if (!Array.isArray(arr)) { - arr = [arr]; + arr = [ arr ]; } arr.push(value); this.set(key, arr, true); @@ -306,7 +306,7 @@ export class Config { } let arr = this.get(key, [], true); if (!Array.isArray(arr)) { - arr = [arr]; + arr = [ arr ]; } arr.unshift(value); this.set(key, arr, true); diff --git a/src/lib/engage/services/install-service.ts b/src/lib/engage/services/install-service.ts index 29c6c66e..a3c8ab61 100644 --- a/src/lib/engage/services/install-service.ts +++ b/src/lib/engage/services/install-service.ts @@ -4,11 +4,10 @@ import * as helpers from '../utils/agents/index.js'; import logger from '../../logger.js'; import { ApiServerClient } from '../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../results/DefinitionsManager.js'; -import { AccountRole, AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BundleType, GatewayTypes, InstallAgentsCommandParams, Regions, SaaSGatewayTypes, YesNo, YesNoChoices } from '../types.js'; -import { askList, InputValidation, validateRegex } from '../utils/basic-prompts.js'; +import { AccountRole, AgentConfigTypes, AgentInstallConfig, AgentTypes, BundleType, GatewayTypes, InstallAgentsCommandParams, InstallationFlowMethods, Regions, SaaSGatewayTypes, YesNo, YesNoChoices } from '../types.js'; +import { askList } from '../utils/basic-prompts.js'; import { loadConfig } from '../../config.js'; import { PlatformClient } from '../clients-external/platformclient.js'; - import * as akamaiAgents from '../utils/agents/flows/akamaiAgent.js'; import * as akamaiSaasAgents from '../utils/agents/flows/akamaiSaasAgents.js'; import * as apigeeXAgents from '../utils/agents/flows/apigeexAgents.js'; @@ -36,36 +35,12 @@ import { Account } from '../../../types.js'; const log = logger('engage:install-service'); -export const localhost = 'localhost'; -export const svcAccMsg - = '\nPlease make sure to copy the "private_key.pem" and "public_key.pem" files for the existing service account you selected.'; - export const prompts = { hostedAgentOption: 'Will this be an embedded agent', selectGatewayType: 'Select the type of gateway you want to connect', }; -export interface InstallationFlowMethods { - GetBundleType: (Gateway?: GatewayTypes) => Promise; - GetDeploymentType: () => Promise; - AskGatewayQuestions: ( - installConfig: AgentInstallConfig, - apiServerClient?: ApiServerClient, - defsManager?: DefinitionsManager - ) => Promise; - InstallPreprocess?: (installConfig: AgentInstallConfig) => Promise; - AddIDP?: boolean; - FinalizeGatewayInstall: ( - installConfig: AgentInstallConfig, - apiServerClient?: ApiServerClient, - defsManager?: DefinitionsManager - ) => Promise; - ConfigFiles: string[]; - AgentNameMap?: { [key in AgentTypes]?: AgentNames }; - GatewayDisplay: GatewayTypes | SaaSGatewayTypes; -} - -const agentInstallFlows: { [key in GatewayTypes]: InstallationFlowMethods } = { +export const agentInstallFlows: { [key in GatewayTypes]: InstallationFlowMethods } = { [GatewayTypes.AKAMAI]: akamaiAgents.AkamaiInstallMethods, [GatewayTypes.EDGE_GATEWAY]: edgeAgents.EdgeInstallMethods, [GatewayTypes.EDGE_GATEWAY_ONLY]: edgeAgents.EdgeGWOnlyInstallMethods, @@ -86,7 +61,7 @@ const agentInstallFlows: { [key in GatewayTypes]: InstallationFlowMethods } = { [GatewayTypes.WSO2]: wso2Agents.WSO2InstallMethods, }; -const saasAgentInstallFlows: { [key: string]: InstallationFlowMethods } = { +export const saasAgentInstallFlows: { [key: string]: InstallationFlowMethods } = { [GatewayTypes.AKAMAI]: akamaiSaasAgents.AkamaiSaaSInstallMethods, [SaaSGatewayTypes.AWS_GATEWAY as string]: awsSaaSAgents.AWSSaaSInstallMethods, [SaaSGatewayTypes.GITHUB]: gitHubAgents.GitHubSaaSInstallMethods, @@ -156,24 +131,6 @@ function checkUserRole(isCentralAdmin: boolean, isPlatformAdmin: boolean, accoun } } -export const validateFrequency = (lowerLimit?: number): InputValidation => (input: string | number) => { - const val = validateRegex(helpers.frequencyRegex, helpers.invalidValueExampleErrMsg('frequency', '3d5h12m'))(input); - if (typeof val === 'string') { - return val; - } - const r = input.toString().match(/^(\d*)m/); - if (r) { - // only minutes - const mins = r[1]; - const minValue = parseInt(mins as string, 10); - const minimumRequired = lowerLimit ?? 30; // Use provided lowerLimit or default to 30 - if (minValue < minimumRequired) { - return `Minimum frequency is ${minimumRequired}m`; - } - } - return true; -}; - export async function installAgents(params: InstallAgentsCommandParams): Promise { try { // initialize clients diff --git a/src/lib/engage/types.ts b/src/lib/engage/types.ts index 47dac493..7d1b888d 100644 --- a/src/lib/engage/types.ts +++ b/src/lib/engage/types.ts @@ -20,6 +20,9 @@ export const MAX_CACHE_FILE_SIZE = 5 * 1024 * 1024; export const CACHE_FILE_TTL_MILLISECONDS = process.env.NODE_ENV === 'test' ? 100 : 60000 * 60 * 12; export const WAIT_TIMEOUT = process.env.NODE_ENV === 'test' ? 1e3 : 1e4; +export const localhost = 'localhost'; +export const svcAccMsg + = '\nPlease make sure to copy the "private_key.pem" and "public_key.pem" files for the existing service account you selected.'; /** * Invoked multiple times to indicate progress on something, such as download progress. @@ -1161,3 +1164,23 @@ export enum TraceableRegionType { Canada = 'Canada', UAE = 'UAE', } + +export interface InstallationFlowMethods { + GetBundleType: (Gateway?: GatewayTypes) => Promise; + GetDeploymentType: () => Promise; + AskGatewayQuestions: ( + installConfig: AgentInstallConfig, + apiServerClient?: ApiServerClient, + defsManager?: DefinitionsManager + ) => Promise; + InstallPreprocess?: (installConfig: AgentInstallConfig) => Promise; + AddIDP?: boolean; + FinalizeGatewayInstall: ( + installConfig: AgentInstallConfig, + apiServerClient?: ApiServerClient, + defsManager?: DefinitionsManager + ) => Promise; + ConfigFiles: string[]; + AgentNameMap?: { [key in AgentTypes]?: AgentNames }; + GatewayDisplay: GatewayTypes | SaaSGatewayTypes; +} diff --git a/src/lib/engage/utils/agents/flows/akamaiAgent.ts b/src/lib/engage/utils/agents/flows/akamaiAgent.ts index bb5888ee..92f04234 100644 --- a/src/lib/engage/utils/agents/flows/akamaiAgent.ts +++ b/src/lib/engage/utils/agents/flows/akamaiAgent.ts @@ -1,8 +1,7 @@ import chalk from 'chalk'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, GenericResource, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, GenericResource, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex, validateValueRange } from '../../basic-prompts.js'; import { AgentHelmInfo, helmImageSecretInfo, helmInstallInfo, isWindows, writeTemplates } from '../../utils.js'; import { AkamaiAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/akamaiSaasAgents.ts b/src/lib/engage/utils/agents/flows/akamaiSaasAgents.ts index 31823bf1..41973d69 100644 --- a/src/lib/engage/utils/agents/flows/akamaiSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/akamaiSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypes, GatewayTypeToDataPlane, GenericResource, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypes, GatewayTypeToDataPlane, GenericResource, InstallationFlowMethods, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex, validateValueRange } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import * as crypto from 'crypto'; diff --git a/src/lib/engage/utils/agents/flows/apigeexAgents.ts b/src/lib/engage/utils/agents/flows/apigeexAgents.ts index 20d1270f..30943272 100644 --- a/src/lib/engage/utils/agents/flows/apigeexAgents.ts +++ b/src/lib/engage/utils/agents/flows/apigeexAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, ApigeeMetricsFilterConfig, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, ApigeeMetricsFilterConfig, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { ApigeeXAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/apigeexSaasAgents.ts b/src/lib/engage/utils/agents/flows/apigeexSaasAgents.ts index a33ffb32..a367799c 100644 --- a/src/lib/engage/utils/agents/flows/apigeexSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/apigeexSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, ApigeeMetricsFilterConfig, APIGEEXAuthType, APIGEEXDISCOVERYMODES, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, ApigeeMetricsFilterConfig, APIGEEXAuthType, APIGEEXDISCOVERYMODES, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, InstallationFlowMethods, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, InputValidation, validateRegex } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import * as crypto from 'crypto'; diff --git a/src/lib/engage/utils/agents/flows/awsAgents.ts b/src/lib/engage/utils/agents/flows/awsAgents.ts index 2cc14539..e97ea2fa 100644 --- a/src/lib/engage/utils/agents/flows/awsAgents.ts +++ b/src/lib/engage/utils/agents/flows/awsAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import fs from 'fs'; import logger from '../../../../logger.js'; import { dataService } from '../../../../request.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, AWSRegions, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, PublicRepoUrl, TrueFalse, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, AWSRegions, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, PublicRepoUrl, TrueFalse, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateInputLength, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates, writeToFile } from '../../utils.js'; import { AWSAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/awsSaasAgents.ts b/src/lib/engage/utils/agents/flows/awsSaasAgents.ts index d32fb599..f8997e82 100644 --- a/src/lib/engage/utils/agents/flows/awsSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/awsSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BundleType, GatewayTypes, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BundleType, GatewayTypes, InstallationFlowMethods, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateInputLength, validateRegex } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import { diff --git a/src/lib/engage/utils/agents/flows/azureAgents.ts b/src/lib/engage/utils/agents/flows/azureAgents.ts index ae5f61db..8be25da5 100644 --- a/src/lib/engage/utils/agents/flows/azureAgents.ts +++ b/src/lib/engage/utils/agents/flows/azureAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { AzureAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/azureSaasAgents.ts b/src/lib/engage/utils/agents/flows/azureSaasAgents.ts index 559548be..f7bf4a46 100644 --- a/src/lib/engage/utils/agents/flows/azureSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/azureSaasAgents.ts @@ -1,7 +1,6 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, AzureDataplaneMode, BundleType, GatewayTypes } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, AzureDataplaneMode, BundleType, GatewayTypes, InstallationFlowMethods } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; diff --git a/src/lib/engage/utils/agents/flows/backstageAgents.ts b/src/lib/engage/utils/agents/flows/backstageAgents.ts index 9e718af9..5925b3e7 100644 --- a/src/lib/engage/utils/agents/flows/backstageAgents.ts +++ b/src/lib/engage/utils/agents/flows/backstageAgents.ts @@ -1,5 +1,4 @@ -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import { AuthMode, BackstageAgentValues, backstageDAEnvVarTemplate, UrlScheme } from '../templates/backstageTemplates.js'; import * as helpers from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/edgeAgents.ts b/src/lib/engage/utils/agents/flows/edgeAgents.ts index b02c9095..661040ad 100644 --- a/src/lib/engage/utils/agents/flows/edgeAgents.ts +++ b/src/lib/engage/utils/agents/flows/edgeAgents.ts @@ -1,8 +1,7 @@ import chalk from 'chalk'; import fs from 'fs'; import { dataService } from '../../../../request.js'; -import { InstallationFlowMethods, localhost, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, LoggingSource, PublicDockerRepoBaseUrl, PublicRepoUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, localhost, LoggingSource, PublicDockerRepoBaseUrl, PublicRepoUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, askUsernameAndPassword } from '../../basic-prompts.js'; import { writeTemplates, isWindows, AgentHelmInfo, helmImageSecretInfo, helmInstallInfo } from '../../utils.js'; import { V7AgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/gitHubSaasAgents.ts b/src/lib/engage/utils/agents/flows/gitHubSaasAgents.ts index ecb63a04..86ff5756 100644 --- a/src/lib/engage/utils/agents/flows/gitHubSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/gitHubSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, InstallationFlowMethods, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, InputValidation, validateRegex } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import * as crypto from 'crypto'; diff --git a/src/lib/engage/utils/agents/flows/gitLabAgents.ts b/src/lib/engage/utils/agents/flows/gitLabAgents.ts index ff65c0e8..42de9bc6 100644 --- a/src/lib/engage/utils/agents/flows/gitLabAgents.ts +++ b/src/lib/engage/utils/agents/flows/gitLabAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { GitLabAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/graylogAgents.ts b/src/lib/engage/utils/agents/flows/graylogAgents.ts index 0ade491d..0aed3f8e 100644 --- a/src/lib/engage/utils/agents/flows/graylogAgents.ts +++ b/src/lib/engage/utils/agents/flows/graylogAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BundleType, GatewayTypes } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BundleType, GatewayTypes, InstallationFlowMethods } from '../../../types.js'; import { askInput, validateRegex } from '../../basic-prompts.js'; import { AgentHelmInfo, helmImageSecretInfo, helmInstallInfo, writeTemplates } from '../../utils.js'; import { GraylogAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/ibmAPIConnetAgents.ts b/src/lib/engage/utils/agents/flows/ibmAPIConnetAgents.ts index e03a975c..af54d20d 100644 --- a/src/lib/engage/utils/agents/flows/ibmAPIConnetAgents.ts +++ b/src/lib/engage/utils/agents/flows/ibmAPIConnetAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { IBMAPIConnectAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/istioAgents.ts b/src/lib/engage/utils/agents/flows/istioAgents.ts index 16443b53..237553a4 100644 --- a/src/lib/engage/utils/agents/flows/istioAgents.ts +++ b/src/lib/engage/utils/agents/flows/istioAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, BundleType, Certificate, GatewayTypes, IstioAgentValues, IstioInstallValues, IstioProfileChoices, Protocol, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, BundleType, Certificate, GatewayTypes, InstallationFlowMethods, IstioAgentValues, IstioInstallValues, IstioProfileChoices, Protocol, YesNo, YesNoChoices } from '../../../types.js'; import { createTlsCert } from '../../bash-commands.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { AgentHelmInfo, helmImageSecretInfo, helmInstallInfo, writeTemplates } from '../../utils.js'; diff --git a/src/lib/engage/utils/agents/flows/kafkaAgents.ts b/src/lib/engage/utils/agents/flows/kafkaAgents.ts index ae9210c5..48504586 100644 --- a/src/lib/engage/utils/agents/flows/kafkaAgents.ts +++ b/src/lib/engage/utils/agents/flows/kafkaAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { KafkaAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/saasAgentsBase.ts b/src/lib/engage/utils/agents/flows/saasAgentsBase.ts index 9281012b..61513362 100644 --- a/src/lib/engage/utils/agents/flows/saasAgentsBase.ts +++ b/src/lib/engage/utils/agents/flows/saasAgentsBase.ts @@ -2,10 +2,9 @@ import chalk from 'chalk'; import * as crypto from 'crypto'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { validateFrequency } from '../../../services/install-service.js'; import { AgentInstallConfig, AgentResourceKind, AgentTypes, CentralAgentConfig, GatewayTypeToDataPlane, GatewayTypes, GenericResource, IDPAuthConfiguration, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex, validateValidRegex } from '../../basic-prompts.js'; -import { FormatString } from '../../utils.js'; +import { FormatString, validateFrequency } from '../../utils.js'; import * as helpers from '../index.js'; export class DataplaneConfig { diff --git a/src/lib/engage/utils/agents/flows/sapApiPortalAgents.ts b/src/lib/engage/utils/agents/flows/sapApiPortalAgents.ts index 19135fd4..2aea7b13 100644 --- a/src/lib/engage/utils/agents/flows/sapApiPortalAgents.ts +++ b/src/lib/engage/utils/agents/flows/sapApiPortalAgents.ts @@ -1,5 +1,4 @@ -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import { SAPApiPortalAgentValues, sapAPIPortalDAEnvVarTemplate, sapAPIPortalTAEnvVarTemplate } from '../templates/sapApiPortalTemplates.js'; import * as helpers from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/sensediaAgents.ts b/src/lib/engage/utils/agents/flows/sensediaAgents.ts index dc87a44b..7ff43c2c 100644 --- a/src/lib/engage/utils/agents/flows/sensediaAgents.ts +++ b/src/lib/engage/utils/agents/flows/sensediaAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { SensediaAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/softwareAGWebMethodAgents.ts b/src/lib/engage/utils/agents/flows/softwareAGWebMethodAgents.ts index 8aed8e63..5697ff3f 100644 --- a/src/lib/engage/utils/agents/flows/softwareAGWebMethodAgents.ts +++ b/src/lib/engage/utils/agents/flows/softwareAGWebMethodAgents.ts @@ -1,6 +1,5 @@ import chalk from 'chalk'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import { isWindows, writeTemplates } from '../../utils.js'; import { SoftwareAGWebMethodsAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/swaggerHubSaasAgents.ts b/src/lib/engage/utils/agents/flows/swaggerHubSaasAgents.ts index f9ed0a20..68f0268b 100644 --- a/src/lib/engage/utils/agents/flows/swaggerHubSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/swaggerHubSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypeToDataPlane, GenericResource, InstallationFlowMethods, SaaSGatewayTypes, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList, InputValidation, validateRegex } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import * as crypto from 'crypto'; diff --git a/src/lib/engage/utils/agents/flows/traceableAgents.ts b/src/lib/engage/utils/agents/flows/traceableAgents.ts index b4e2c612..fb1ccd80 100644 --- a/src/lib/engage/utils/agents/flows/traceableAgents.ts +++ b/src/lib/engage/utils/agents/flows/traceableAgents.ts @@ -1,8 +1,7 @@ import chalk from 'chalk'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, GenericResource, PublicDockerRepoBaseUrl, TraceableRegionType, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, GenericResource, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg, TraceableRegionType, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import { AgentHelmInfo, helmImageSecretInfo, helmInstallInfo, isWindows, writeTemplates } from '../../utils.js'; import { TraceableAgentValues } from '../index.js'; diff --git a/src/lib/engage/utils/agents/flows/traceableSaasAgents.ts b/src/lib/engage/utils/agents/flows/traceableSaasAgents.ts index cf43035d..04fa4aa8 100644 --- a/src/lib/engage/utils/agents/flows/traceableSaasAgents.ts +++ b/src/lib/engage/utils/agents/flows/traceableSaasAgents.ts @@ -2,8 +2,7 @@ import chalk from 'chalk'; import logger from '../../../../logger.js'; import { ApiServerClient } from '../../../clients-external/apiserverclient.js'; import { DefinitionsManager } from '../../../results/DefinitionsManager.js'; -import { InstallationFlowMethods } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypes, GatewayTypeToDataPlane, GenericResource, SaaSGatewayTypes, TraceableRegionType, YesNo, YesNoChoices } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentResourceKind, AgentTypes, BundleType, CentralAgentConfig, GatewayTypes, GatewayTypeToDataPlane, GenericResource, InstallationFlowMethods, SaaSGatewayTypes, TraceableRegionType, YesNo, YesNoChoices } from '../../../types.js'; import { askInput, askList } from '../../basic-prompts.js'; import * as helpers from '../index.js'; import * as crypto from 'crypto'; diff --git a/src/lib/engage/utils/agents/flows/wso2Agents.ts b/src/lib/engage/utils/agents/flows/wso2Agents.ts index b9703b3b..3f1a9ed1 100644 --- a/src/lib/engage/utils/agents/flows/wso2Agents.ts +++ b/src/lib/engage/utils/agents/flows/wso2Agents.ts @@ -1,5 +1,4 @@ -import { InstallationFlowMethods, svcAccMsg } from '../../../services/install-service.js'; -import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, PublicDockerRepoBaseUrl } from '../../../types.js'; +import { AgentConfigTypes, AgentInstallConfig, AgentNames, AgentTypes, BasePaths, BundleType, GatewayTypes, InstallationFlowMethods, PublicDockerRepoBaseUrl, svcAccMsg } from '../../../types.js'; import { askInput, askList, validateRegex } from '../../basic-prompts.js'; import { WSO2AgentValues, wso2DAEnvVarTemplate, wso2TAEnvVarTemplate } from '../templates/wso2Templates.js'; import * as helpers from '../index.js'; diff --git a/src/lib/engage/utils/bash-commands.ts b/src/lib/engage/utils/bash-commands.ts index 90b79d0d..c3f7698f 100644 --- a/src/lib/engage/utils/bash-commands.ts +++ b/src/lib/engage/utils/bash-commands.ts @@ -80,10 +80,13 @@ export const createTlsCert = async ( return { cert, privateKey }; }; -export const editor = (editor: string, filePath: string): Promise => { +export const editor = (editorCmd: string, filePath: string): Promise => { log.log(`editor ${filePath}`); + // editorCmd may be a multi-word string like "node /path/to/script.js"; split into + // executable + pre-defined args so that shell:true is not required. + const [ cmd, ...editorArgs ] = editorCmd.split(' '); return new Promise((resolve) => { - spawn(editor, [ filePath ], { stdio: 'inherit' }).on('exit', (code) => { + spawn(cmd, [ ...editorArgs, filePath ], { stdio: 'inherit' }).on('exit', (code) => { log.log(`editor exit code ${code}`); resolve(code); }); diff --git a/src/lib/engage/utils/basic-prompts.ts b/src/lib/engage/utils/basic-prompts.ts index 159aa74d..6f99409f 100644 --- a/src/lib/engage/utils/basic-prompts.ts +++ b/src/lib/engage/utils/basic-prompts.ts @@ -168,6 +168,25 @@ export const askList = async (opts: { const choices = opts.choices.map((c) => (typeof c === 'string' ? { value: c, name: c } : c) ) as (Separator | { value: string; name?: string })[]; + const testResponse = process.env.AXWAY_TEST_ASK_LIST_RESPONSE; + if (testResponse !== undefined) { + for (const choice of choices) { + if (choice instanceof Separator) { + continue; + } + if (choice.value === testResponse || choice.name === testResponse) { + return choice.value; + } + } + if (opts.default !== undefined) { + return opts.default; + } + for (const choice of choices) { + if (!(choice instanceof Separator)) { + return choice.value; + } + } + } return select({ message: `${opts.msg}: `, choices, diff --git a/src/lib/engage/utils/tmp-file.ts b/src/lib/engage/utils/tmp-file.ts index be17fbe4..a1e24f2f 100644 --- a/src/lib/engage/utils/tmp-file.ts +++ b/src/lib/engage/utils/tmp-file.ts @@ -56,14 +56,15 @@ export default class TmpFile { /** * Open file in editor and return promise with flags indicating if edit was successful or not * (process killed, vim q! happened etc. ), and if file content has been changed or not. - * Using vim or "EDITOR" env on linux and only notepad on windows. + * Respects the EDITOR environment variable on all platforms; falls back to notepad on + * Windows or vi on Unix. * @returns {object} represent result of editing: * isComplete: editor process completed successfully * isUpdated: content of the file changed */ async edit(): Promise<{ isComplete: boolean; isUpdated: boolean }> { log.log(`editing: ${this.path}`); - const editorToUse = isWindows ? 'notepad' : process.env.EDITOR || 'vi'; + const editorToUse = process.env.EDITOR || (isWindows ? 'notepad' : 'vi'); const contentBeforeEdit = Buffer.from(this.read()); const editorExitCode = await editor(editorToUse, this.path); const isUpdated = !contentBeforeEdit.equals(Buffer.from(this.read())); diff --git a/src/lib/engage/utils/utils.ts b/src/lib/engage/utils/utils.ts index c9166ad3..6acc5373 100644 --- a/src/lib/engage/utils/utils.ts +++ b/src/lib/engage/utils/utils.ts @@ -5,6 +5,8 @@ import { loadAll } from 'js-yaml'; import chalk from 'chalk'; import hbs from 'handlebars'; +import { InputValidation, validateRegex } from './basic-prompts.js'; +import { frequencyRegex } from './agents/regex.js'; import { ApiServerError, ApiServerErrorResponse, @@ -27,6 +29,23 @@ import { CompositeError } from '../results/compositeerror.js'; export const isWindows = /^win/.test(process.platform); +export const validateFrequency = (lowerLimit?: number): InputValidation => (input: string | number) => { + const val = validateRegex(frequencyRegex, 'Invalid frequency entered. frequency must be in the form of 3d5h12m')(input); + if (typeof val === 'string') { + return val; + } + const r = input.toString().match(/^(\d*)m/); + if (r) { + const mins = r[1]; + const minValue = parseInt(mins as string, 10); + const minimumRequired = lowerLimit ?? 30; + if (minValue < minimumRequired) { + return `Minimum frequency is ${minimumRequired}m`; + } + } + return true; +}; + export const writeToFile = (path: string, data: any): void => { try { writeFileSync(path, data); diff --git a/src/lib/update.ts b/src/lib/update.ts index 2c5cd8a3..bfa5505a 100644 --- a/src/lib/update.ts +++ b/src/lib/update.ts @@ -8,6 +8,7 @@ import { readJsonSync, writeFileSync } from './fs.js'; const { error, log, warn } = logger('update'); +// eslint-disable-next-line import/no-mutable-exports export let pendingCheck: Promise; interface UpdateMeta { diff --git a/test/commands/engage/apply/templates/autogenerated-name.mustache b/test/commands/engage/apply/templates/autogenerated-name.mustache new file mode 100644 index 00000000..70cc32b0 --- /dev/null +++ b/test/commands/engage/apply/templates/autogenerated-name.mustache @@ -0,0 +1 @@ +⚠ "{{string}}" was created with an autogenerated logical name. diff --git a/test/commands/engage/apply/templates/create-success.mustache b/test/commands/engage/apply/templates/create-success.mustache new file mode 100644 index 00000000..db22f3ac --- /dev/null +++ b/test/commands/engage/apply/templates/create-success.mustache @@ -0,0 +1,4 @@ +{{check}} "Environment/{{string}}" has successfully been created. +{{check}} "APIService/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Secret/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Webhook/{{string}}" in the scope "Environment/{{string}}" has successfully been created. diff --git a/test/commands/engage/apply/templates/create-update-success-v1.mustache b/test/commands/engage/apply/templates/create-update-success-v1.mustache new file mode 100644 index 00000000..9abcc5d1 --- /dev/null +++ b/test/commands/engage/apply/templates/create-update-success-v1.mustache @@ -0,0 +1,4 @@ +{{check}} "Environment/{{string}}" has successfully been updated. +{{check}} "APIService/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Secret/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Webhook/{{string}}" in the scope "Environment/{{string}}" has successfully been updated. diff --git a/test/commands/engage/apply/templates/create-update-success.mustache b/test/commands/engage/apply/templates/create-update-success.mustache new file mode 100644 index 00000000..1a1a24e6 --- /dev/null +++ b/test/commands/engage/apply/templates/create-update-success.mustache @@ -0,0 +1,4 @@ +{{check}} "Environment/{{string}}" has successfully been updated. +{{check}} "APIService/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Secret/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Webhook/{{string}}" in the scope "Environment/{{string}}" has successfully been created. diff --git a/test/commands/engage/apply/templates/file-required.mustache b/test/commands/engage/apply/templates/file-required.mustache new file mode 100644 index 00000000..b2af0c19 --- /dev/null +++ b/test/commands/engage/apply/templates/file-required.mustache @@ -0,0 +1 @@ +{{x}} Error: File name is required diff --git a/test/commands/engage/apply/templates/help.mustache b/test/commands/engage/apply/templates/help.mustache new file mode 100644 index 00000000..6711da56 --- /dev/null +++ b/test/commands/engage/apply/templates/help.mustache @@ -0,0 +1,5 @@ +AXWAY CLI, version {{version}} +Copyright (c) 2018-{{year}}, Axway, Inc. All Rights Reserved.{{{nodeDeprecationWarning}}} +Update resources from a file. + +USAGE diff --git a/test/commands/engage/apply/templates/not-authenticated.mustache b/test/commands/engage/apply/templates/not-authenticated.mustache new file mode 100644 index 00000000..b5074f74 --- /dev/null +++ b/test/commands/engage/apply/templates/not-authenticated.mustache @@ -0,0 +1 @@ +{{x}} Error: You must be authenticated diff --git a/test/commands/engage/apply/templates/partial-400-error.mustache b/test/commands/engage/apply/templates/partial-400-error.mustache new file mode 100644 index 00000000..bfcd6489 --- /dev/null +++ b/test/commands/engage/apply/templates/partial-400-error.mustache @@ -0,0 +1,4 @@ +{{check}} "Environment/{{string}}" has successfully been created. +{{x}} "APIService/{{string}}" Validation error: Name is not valid. +{{check}} "Secret/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Webhook/{{string}}" in the scope "Environment/{{string}}" has successfully been created. diff --git a/test/commands/engage/apply/templates/resource-updated.mustache b/test/commands/engage/apply/templates/resource-updated.mustache new file mode 100644 index 00000000..3306a2ac --- /dev/null +++ b/test/commands/engage/apply/templates/resource-updated.mustache @@ -0,0 +1 @@ +{{check}} "Environment/{{string}}" has successfully been {{string}}. diff --git a/test/commands/engage/apply/templates/server-error.mustache b/test/commands/engage/apply/templates/server-error.mustache new file mode 100644 index 00000000..2b230d6d --- /dev/null +++ b/test/commands/engage/apply/templates/server-error.mustache @@ -0,0 +1 @@ +{{x}} Error: ApiServer error diff --git a/test/commands/engage/apply/templates/subresource-updated.mustache b/test/commands/engage/apply/templates/subresource-updated.mustache new file mode 100644 index 00000000..b5526947 --- /dev/null +++ b/test/commands/engage/apply/templates/subresource-updated.mustache @@ -0,0 +1 @@ +{{check}} "{{string}}" subresource "{{string}}" has successfully been updated. diff --git a/test/commands/engage/apply/templates/validation-error.mustache b/test/commands/engage/apply/templates/validation-error.mustache new file mode 100644 index 00000000..8bef5b95 --- /dev/null +++ b/test/commands/engage/apply/templates/validation-error.mustache @@ -0,0 +1 @@ +{{string}} Validation error diff --git a/test/commands/engage/apply/test-apply.js b/test/commands/engage/apply/test-apply.js new file mode 100644 index 00000000..a2672d05 --- /dev/null +++ b/test/commands/engage/apply/test-apply.js @@ -0,0 +1,297 @@ +import path from 'path'; +import { runCommand, renderRegexFromFile } from '../../../helpers/index.js'; +import { + engageEnv, + testDataDir, + e400, + e500, + setupEngageAuth, + initHomeDir, + resetHomeDir, +} from '../../../helpers/engage-test-helper.js'; + +describe('axway engage apply', () => { + describe('help', () => { + it('should output the help screen', async () => { + const { status, stdout } = await runCommand([ 'engage', 'apply', '--help' ]); + expect(stdout).to.match(renderRegexFromFile('templates/help')); + expect(status).to.equal(0); + }); + }); + + describe('auth required', () => { + afterEach(resetHomeDir); + + it('should error if not authenticated', async () => { + initHomeDir('home-local'); + // home-local has valid config but no login tokens + const { status, stderr } = await runCommand([ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], { env: engageEnv }); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/not-authenticated')); + }); + }); + + describe('authenticated', () => { + /** @type {any} */ + let engageServer; + + beforeEach(async function () { + engageServer = await setupEngageAuth.call(this); + }); + + afterEach(resetHomeDir); + + it('should error if --file flag is not provided', async () => { + const { status, stderr } = await runCommand([ 'engage', 'apply' ], { env: engageEnv }); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/file-required')); + }); + + it('should create and update resources from yaml', async () => { + // Pre-seed env as existing (to trigger update path) — others will be created + const envResponse = { + group: 'management', + apiVersion: 'v1alpha1', + kind: 'Environment', + name: 'testenv1', + title: 'testenv1 title', + metadata: { id: 'abc123', resourceVersion: '1', references: [] }, + spec: { description: 'testenv1 description' }, + }; + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', envResponse); + + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + + // Env was updated (pre-existed), others were created + expect(stderr).to.match(renderRegexFromFile('templates/create-update-success')); + expect(status).to.equal(0); + }); + + it('should create and update resources from yaml with v1 apiVersion', async () => { + // Pre-seed env and webhook to trigger update path; APIService and Secret will be created + const envResponse = { group: 'management', apiVersion: 'v1', kind: 'Environment', name: 'testenv1', metadata: { id: 'abc123', resourceVersion: '1', references: [] }, spec: {} }; + const webhookResponse = { group: 'management', apiVersion: 'v1', kind: 'Webhook', name: 'webhook1', metadata: { scope: { kind: 'Environment', name: 'testenv1' }, resourceVersion: '1', references: [] }, spec: {} }; + engageServer.engageResources.set('management/v1/environments/testenv1', envResponse); + engageServer.engageResources.set('management/v1/environments/testenv1/webhooks/webhook1', webhookResponse); + + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstancesV1short.yaml') ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/create-update-success-v1')); + }); + + it('should create resources with --output yaml flag', async () => { + const { status, stdout } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.yaml'), '--output', 'yaml' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stdout).to.match(/kind:\s*Environment/); + }); + + it('should create resources with --output json flag', async () => { + const { status, stdout } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.json'), '--output', 'json', '--no-banner' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + const parsed = JSON.parse(stdout); + expect(parsed).to.be.an('array').with.length.greaterThan(0); + }); + + it('should skip prompt and create resources with missing names when --yes flag is provided', async () => { + const { status, stderr } = await runCommand( + [ + 'engage', 'apply', + '--file', path.join(testDataDir, 'testInstancesWithMissingLogicalNames.yaml'), + '--yes', + ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/autogenerated-name')); + }); + + it('should proceed when prompt is bypassed via AXWAY_TEST_ASK_LIST_RESPONSE=Yes', async () => { + // Without --yes, askList() is called. The env var makes it return 'Yes' + // so the batch continues. Note: success messages are silently dropped + // when spinner=null (set by stopSpin inside onMissingNames), so we + // verify exit code rather than output content. + const { status } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstancesWithMissingLogicalNames.yaml') ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'Yes' } } + ); + expect(status).to.equal(0); + }); + + it('should abort when prompt is answered No via AXWAY_TEST_ASK_LIST_RESPONSE=No', async () => { + const { status } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstancesWithMissingLogicalNames.yaml') ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'No' } } + ); + expect(status).to.equal(0); + }); + + it('should create and update assets with sub-resources with --output yaml', async () => { + // Pre-seed asset1 to trigger update; asset2 will be created + engageServer.engageResources.set('catalog/v1alpha1/assets/testasset1', { + group: 'catalog', apiVersion: 'v1alpha1', kind: 'Asset', name: 'testasset1', + metadata: { id: 'id1', resourceVersion: '1', references: [] }, spec: { type: 'API' }, + }); + + const { status, stdout } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'byKind/Asset/input.yaml'), '--output', 'yaml' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stdout).to.match(/kind:\s*Asset/); + expect(stdout).to.include('testasset1'); + expect(stdout).to.include('testasset2'); + }); + + it('should create assets without names using --yes and get autogenerated names', async () => { + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'byKind/Asset/input-without-names.yaml'), '--yes' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/autogenerated-name')); + }); + + it('should update only the specified --subresource', async () => { + // Pre-seed both assets so GET returns 200 (update path) + engageServer.engageResources.set('catalog/v1alpha1/assets/testasset1', { + group: 'catalog', apiVersion: 'v1alpha1', kind: 'Asset', name: 'testasset1', + metadata: { id: 'id1', resourceVersion: '1', references: [] }, spec: { type: 'API' }, + icon: 'data:image/svg+xml;base64,111', state: 'state 111', 'x-custom': 111, + }); + engageServer.engageResources.set('catalog/v1alpha1/assets/testasset2', { + group: 'catalog', apiVersion: 'v1alpha1', kind: 'Asset', name: 'testasset2', + metadata: { id: 'id2', resourceVersion: '1', references: [] }, spec: { type: 'API' }, + icon: 'data:image/svg+xml;base64,222', state: 'state 222', 'x-custom': 222, + }); + + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'byKind/Asset/input.yaml'), '--subresource', 'icon' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/subresource-updated')); + }); + + it('should update product with French language sub-resource', async () => { + // Pre-seed product so GET returns 200 (update path) + engageServer.engageResources.set('catalog/v1alpha1/products/test-product-1', { + group: 'catalog', apiVersion: 'v1alpha1', kind: 'Product', name: 'test-product-1', + metadata: { id: 'prod1', resourceVersion: '15', references: [] }, spec: { assets: [] }, + }); + + const { status, stdout } = await runCommand( + [ + 'engage', 'apply', + '--file', path.join(testDataDir, 'apiResponses/frenchLanguageDefinition.json'), + '--output', 'json', + '--language', 'fr-fr', + '--no-banner', + ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + const parsed = JSON.parse(stdout); + expect(parsed).to.be.an('array').with.length.greaterThan(0); + expect(JSON.stringify(parsed)).to.include('test-product-1'); + }); + + it('should create product with French language sub-resource', async () => { + // No pre-seeded product → POST (create path) + const { status, stdout } = await runCommand( + [ + 'engage', 'apply', + '--file', path.join(testDataDir, 'apiResponses/frenchLanguageDefinition.json'), + '--output', 'json', + '--language', 'fr-fr', + '--no-banner', + ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + const parsed = JSON.parse(stdout); + expect(parsed).to.be.an('array').with.length.greaterThan(0); + expect(JSON.stringify(parsed)).to.include('test-product-1'); + }); + + it('should exit with code 1 when one resource fails with 400 but others succeed', async () => { + // All GETs return 404 (create path); force APIService POST to return 400 + engageServer.forceErrors.set('POST:management/v1alpha1/environments/testenv1/apiservices', { status: 400, body: e400 }); + + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/partial-400-error')); + }); + + it('should exit with code 1 on 500 error from server mid-batch', async () => { + // Force secrets GET to return 500 + engageServer.forceErrors.set('GET:management/v1alpha1/environments/testenv1/secrets/secret1', { status: 500, body: e500 }); + + const { status, stderr } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/server-error')); + }); + + it('should exit with code 1 when a sub-resource update returns 400', async () => { + // Pre-seed asset1 (update path); force asset2 state sub-resource PUT to fail + engageServer.engageResources.set('catalog/v1alpha1/assets/testasset1', { + group: 'catalog', apiVersion: 'v1alpha1', kind: 'Asset', name: 'testasset1', + metadata: { id: 'id1', resourceVersion: '1', references: [] }, spec: { type: 'API' }, + }); + engageServer.forceErrors.set('PUT:catalog/v1alpha1/assets/testasset2/state', { status: 400, body: e400 }); + + const { status, stdout } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'byKind/Asset/input.yaml'), '--output', 'yaml' ], + { env: engageEnv } + ); + + expect(status).to.equal(1); + // With --output yaml, messages go to stdout (renderer uses this.console not spinner) + expect(stdout).to.match(renderRegexFromFile('templates/validation-error')); + }); + + it('should exit with code 1 on a 400 server error for one resource', async () => { + const { status } = await runCommand( + [ 'engage', 'apply', '--file', path.join(testDataDir, 'testInstances1short.json'), '--output', 'json' ], + { + env: { + ...engageEnv, + // Use a non-existing server to trigger error quickly + AXWAY_CENTRAL_BASE_URL: 'http://127.0.0.1:19999', + }, + } + ); + + expect(status).to.equal(1); + }); + }); +}); + diff --git a/test/commands/engage/create/templates/autogenerated-name.mustache b/test/commands/engage/create/templates/autogenerated-name.mustache new file mode 100644 index 00000000..70cc32b0 --- /dev/null +++ b/test/commands/engage/create/templates/autogenerated-name.mustache @@ -0,0 +1 @@ +⚠ "{{string}}" was created with an autogenerated logical name. diff --git a/test/commands/engage/create/templates/bulk-create-success.mustache b/test/commands/engage/create/templates/bulk-create-success.mustache new file mode 100644 index 00000000..db22f3ac --- /dev/null +++ b/test/commands/engage/create/templates/bulk-create-success.mustache @@ -0,0 +1,4 @@ +{{check}} "Environment/{{string}}" has successfully been created. +{{check}} "APIService/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Secret/{{string}}" in the scope "Environment/{{string}}" has successfully been created. +{{check}} "Webhook/{{string}}" in the scope "Environment/{{string}}" has successfully been created. diff --git a/test/commands/engage/create/templates/file-required.mustache b/test/commands/engage/create/templates/file-required.mustache new file mode 100644 index 00000000..b2af0c19 --- /dev/null +++ b/test/commands/engage/create/templates/file-required.mustache @@ -0,0 +1 @@ +{{x}} Error: File name is required diff --git a/test/commands/engage/create/templates/help.mustache b/test/commands/engage/create/templates/help.mustache new file mode 100644 index 00000000..acfdbf89 --- /dev/null +++ b/test/commands/engage/create/templates/help.mustache @@ -0,0 +1,5 @@ +AXWAY CLI, version {{version}} +Copyright (c) 2018-{{year}}, Axway, Inc. All Rights Reserved.{{{nodeDeprecationWarning}}} +Create one or more resources from a file or stdin. + +USAGE diff --git a/test/commands/engage/create/templates/not-authenticated.mustache b/test/commands/engage/create/templates/not-authenticated.mustache new file mode 100644 index 00000000..b5074f74 --- /dev/null +++ b/test/commands/engage/create/templates/not-authenticated.mustache @@ -0,0 +1 @@ +{{x}} Error: You must be authenticated diff --git a/test/commands/engage/create/templates/server-error.mustache b/test/commands/engage/create/templates/server-error.mustache new file mode 100644 index 00000000..2b230d6d --- /dev/null +++ b/test/commands/engage/create/templates/server-error.mustache @@ -0,0 +1 @@ +{{x}} Error: ApiServer error diff --git a/test/commands/engage/create/templates/validation-error.mustache b/test/commands/engage/create/templates/validation-error.mustache new file mode 100644 index 00000000..8bef5b95 --- /dev/null +++ b/test/commands/engage/create/templates/validation-error.mustache @@ -0,0 +1 @@ +{{string}} Validation error diff --git a/test/commands/engage/create/test-create.js b/test/commands/engage/create/test-create.js new file mode 100644 index 00000000..f7384086 --- /dev/null +++ b/test/commands/engage/create/test-create.js @@ -0,0 +1,159 @@ +import path from 'path'; +import { runCommand, renderRegexFromFile } from '../../../helpers/index.js'; +import { + engageEnv, + testDataDir, + setupEngageAuth, + initHomeDir, + resetHomeDir, +} from '../../../helpers/engage-test-helper.js'; + +describe('axway engage create', () => { + describe('help', () => { + it('should output the help screen', async () => { + const { status, stdout } = await runCommand([ 'engage', 'create', '--help' ]); + expect(stdout).to.match(renderRegexFromFile('templates/help')); + expect(status).to.equal(0); + }); + }); + + describe('auth required', () => { + afterEach(resetHomeDir); + + it('should error if not authenticated', async () => { + initHomeDir('home-local'); + const { status, stderr } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/not-authenticated')); + }); + }); + + describe('authenticated', () => { + /** @type {any} */ + let engageServer; + + beforeEach(async function () { + engageServer = await setupEngageAuth.call(this); + }); + + afterEach(resetHomeDir); + + // --- bulk create from file --- + + describe('bulk create from file', () => { + it('should error if --file flag is not provided', async () => { + const { status, stderr } = await runCommand([ 'engage', 'create' ], { env: engageEnv }); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/file-required')); + }); + + it('should create resources from yaml', async () => { + const { status, stderr } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + expect(stderr).to.match(renderRegexFromFile('templates/bulk-create-success')); + expect(status).to.equal(0); + }); + + it('should create resources with --output yaml', async () => { + const { status, stdout } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.yaml'), '--output', 'yaml' ], + { env: engageEnv } + ); + expect(status).to.equal(0); + expect(stdout).to.match(/kind:\s*Environment/); + expect(stdout).to.include('testenv1'); + }); + + it('should create resources with --output json', async () => { + const { status, stdout } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.json'), '--output', 'json', '--no-banner' ], + { env: engageEnv } + ); + expect(status).to.equal(0); + const parsed = JSON.parse(stdout); + expect(parsed).to.be.an('array').with.length.greaterThan(0); + }); + + it('should create resources with missing logical names with --yes flag', async () => { + const { status, stderr } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'envsWithoutLogicalNames.yaml'), '--yes' ], + { env: engageEnv } + ); + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/autogenerated-name')); + }); + + it('should prompt for missing logical names and proceed when answered Yes', async () => { + const { status } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'envsWithoutLogicalNames.yaml') ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'Yes' } } + ); + expect(status).to.equal(0); + }); + + it('should abort when missing-name prompt is answered No', async () => { + const { status } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'envsWithoutLogicalNames.yaml') ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'No' } } + ); + expect(status).to.equal(0); + }); + + it('should report 400 validation error on resource creation', async () => { + engageServer.forceErrors.set( + 'POST:management/v1alpha1/environments', + { status: 400, body: { errors: [ { status: 400, title: 'Validation error', detail: 'Name is not valid.' } ] } } + ); + const { status, stderr } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/validation-error')); + }); + + it('should report 500 server error on resource creation', async () => { + engageServer.forceErrors.set( + 'POST:management/v1alpha1/environments', + { status: 500, body: { errors: [ { status: 500, title: 'ApiServer error', detail: 'Internal error.' } ] } } + ); + const { status } = await runCommand( + [ 'engage', 'create', '--file', path.join(testDataDir, 'testInstances1short.yaml') ], + { env: engageEnv } + ); + expect(status).to.equal(1); + }); + }); + + // --- create environment by name --- + + describe('create environment by name', () => { + it('should create a single environment', async () => { + const { status } = await runCommand( + [ 'engage', 'create', 'environment', 'testenv1' ], + { env: engageEnv } + ); + expect(status).to.equal(0); + expect(engageServer.engageResources.has('management/v1alpha1/environments/testenv1')).to.be.true; + }); + + it('should report 400 error when creating environment by name', async () => { + engageServer.forceErrors.set( + 'POST:management/v1alpha1/environments', + { status: 400, body: { errors: [ { status: 400, title: 'Validation error', detail: 'Name is not valid.' } ] } } + ); + const { status, stderr } = await runCommand( + [ 'engage', 'create', 'environment', 'bad-name' ], + { env: engageEnv } + ); + expect(status).to.equal(1); + expect(stderr).to.include('Validation error'); + }); + }); + }); +}); diff --git a/test/commands/engage/delete/templates/bulk-delete-success.mustache b/test/commands/engage/delete/templates/bulk-delete-success.mustache new file mode 100644 index 00000000..2a4eff09 --- /dev/null +++ b/test/commands/engage/delete/templates/bulk-delete-success.mustache @@ -0,0 +1,2 @@ +{{check}} "Environment/{{string}}" has successfully been deleted. +{{check}} "Environment/{{string}}" has successfully been deleted. diff --git a/test/commands/engage/delete/templates/delete-success.mustache b/test/commands/engage/delete/templates/delete-success.mustache new file mode 100644 index 00000000..ac608ce0 --- /dev/null +++ b/test/commands/engage/delete/templates/delete-success.mustache @@ -0,0 +1 @@ +{{check}} "Environment/{{string}}" has successfully been deleted. diff --git a/test/commands/engage/delete/templates/help.mustache b/test/commands/engage/delete/templates/help.mustache new file mode 100644 index 00000000..bf7d425d --- /dev/null +++ b/test/commands/engage/delete/templates/help.mustache @@ -0,0 +1,5 @@ +AXWAY CLI, version {{version}} +Copyright (c) 2018-{{year}}, Axway, Inc. All Rights Reserved.{{{nodeDeprecationWarning}}} +Delete resources. + +USAGE diff --git a/test/commands/engage/delete/templates/missing-args.mustache b/test/commands/engage/delete/templates/missing-args.mustache new file mode 100644 index 00000000..fbd7cc1a --- /dev/null +++ b/test/commands/engage/delete/templates/missing-args.mustache @@ -0,0 +1 @@ +{{x}} Error: You must specify the type and name of the resource to delete or a file path. diff --git a/test/commands/engage/delete/templates/not-authenticated.mustache b/test/commands/engage/delete/templates/not-authenticated.mustache new file mode 100644 index 00000000..b5074f74 --- /dev/null +++ b/test/commands/engage/delete/templates/not-authenticated.mustache @@ -0,0 +1 @@ +{{x}} Error: You must be authenticated diff --git a/test/commands/engage/delete/test-delete.js b/test/commands/engage/delete/test-delete.js new file mode 100644 index 00000000..9c70e3a8 --- /dev/null +++ b/test/commands/engage/delete/test-delete.js @@ -0,0 +1,218 @@ +import path from 'path'; +import { runCommand, renderRegexFromFile } from '../../../helpers/index.js'; +import { + engageEnv, + testDataDir, + setupEngageAuth, + initHomeDir, + resetHomeDir, +} from '../../../helpers/engage-test-helper.js'; + +function makeEnv(name) { + return { + group: 'management', + apiVersion: 'v1alpha1', + kind: 'Environment', + name, + title: `${name} title`, + metadata: { + id: `id-${name}`, + audit: { + createTimestamp: '2023-01-01T00:00:00.000Z', + modifyTimestamp: '2023-01-01T00:00:00.000Z', + }, + references: [], + }, + spec: {}, + }; +} + +function makeSecret(name, scopeName) { + return { + group: 'management', + apiVersion: 'v1alpha1', + kind: 'Secret', + name, + title: `${name} title`, + metadata: { + id: `id-${name}`, + audit: { + createTimestamp: '2023-01-01T00:00:00.000Z', + modifyTimestamp: '2023-01-01T00:00:00.000Z', + }, + scope: { kind: 'Environment', name: scopeName }, + references: [], + }, + spec: {}, + }; +} + +describe('axway engage delete', () => { + describe('help', () => { + it('should output the help screen', async () => { + const { status, stdout } = await runCommand([ 'engage', 'delete', '--help' ]); + expect(stdout).to.match(renderRegexFromFile('templates/help')); + expect(status).to.equal(0); + }); + }); + + describe('auth required', () => { + afterEach(resetHomeDir); + + it('should error if not authenticated', async () => { + initHomeDir('home-local'); + const { status, stderr } = await runCommand( + [ 'engage', 'delete', 'environment', 'testenv1', '--yes' ], + { env: engageEnv } + ); + expect(status).to.equal(1); + expect(stderr).to.match(renderRegexFromFile('templates/not-authenticated')); + }); + }); + + describe('authenticated', () => { + /** @type {any} */ + let engageServer; + + beforeEach(async function () { + engageServer = await setupEngageAuth.call(this); + }); + + afterEach(resetHomeDir); + + describe('args validation', () => { + it('should error if no args or --file provided', async () => { + const { status, stdout, stderr } = await runCommand([ 'engage', 'delete' ], { env: engageEnv }); + expect(status).to.equal(1); + expect(stdout + stderr).to.include('You must specify the type and name of the resource to delete or a file path'); + }); + }); + + describe('delete by name', () => { + it('should delete an unscoped resource with --yes (no confirmation prompt)', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', makeEnv('testenv1')); + + const { status, stdout, stderr } = await runCommand( + [ 'engage', 'delete', 'environment', 'testenv1', '--yes' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stdout + stderr).to.include('has successfully been deleted'); + expect(engageServer.engageResources.has('management/v1alpha1/environments/testenv1')).to.be.false; + }); + + it('should delete when confirmation prompt is answered Yes', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', makeEnv('testenv1')); + + const { status } = await runCommand( + [ 'engage', 'delete', 'environment', 'testenv1' ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'Yes' } } + ); + + expect(status).to.equal(0); + expect(engageServer.engageResources.has('management/v1alpha1/environments/testenv1')).to.be.false; + }); + + it('should abort deletion when confirmation prompt is answered No', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', makeEnv('testenv1')); + + const { status } = await runCommand( + [ 'engage', 'delete', 'environment', 'testenv1' ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'No' } } + ); + + // User declined – command exits with error and without deleting. + expect(status).to.equal(1); + expect(engageServer.engageResources.has('management/v1alpha1/environments/testenv1')).to.be.true; + }); + + it('should force-delete an unscoped resource with --force-delete and --yes', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', makeEnv('testenv1')); + + const { status } = await runCommand( + [ 'engage', 'delete', 'environment', 'testenv1', '--yes', '--force-delete' ], + { env: { ...engageEnv, AXWAY_TEST_ASK_LIST_RESPONSE: 'Yes' } } + ); + + expect(status).to.equal(1); + }); + + it('should delete a scoped resource with explicit scope kind and --yes', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/testenv1', makeEnv('testenv1')); + engageServer.engageResources.set('management/v1alpha1/environments/testenv1/secrets/secret1', makeSecret('secret1', 'testenv1')); + + const { status } = await runCommand( + [ 'engage', 'delete', 'secret', 'secret1', '--scope', 'Environment/testenv1', '--yes' ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(engageServer.engageResources.has('management/v1alpha1/environments/testenv1/secrets/secret1')).to.be.false; + }); + + it('should error if resource is not found', async () => { + // resource not seeded → mock server returns 404 + const { status, stderr } = await runCommand( + [ 'engage', 'delete', 'environment', 'nonexistent', '--yes' ], + { env: engageEnv } + ); + + expect(status).to.equal(1); + expect(stderr).to.include('not found'); + }); + + it('should error if an invalid resource type is provided', async () => { + const { status, stderr } = await runCommand( + [ 'engage', 'delete', 'invalidtype123', 'somename', '--yes' ], + { env: engageEnv } + ); + + expect(status).to.equal(1); + expect(stderr).to.include('invalidtype123'); + }); + }); + + describe('delete from file', () => { + it('should bulk-delete resources from a yaml file', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/env1', makeEnv('env1')); + engageServer.engageResources.set('management/v1alpha1/environments/env2', makeEnv('env2')); + + const { status, stderr } = await runCommand( + [ 'engage', 'delete', '--file', path.join(testDataDir, '../examples/environments.yaml') ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + expect(stderr).to.match(renderRegexFromFile('templates/bulk-delete-success')); + expect(engageServer.engageResources.has('management/v1alpha1/environments/env1')).to.be.false; + expect(engageServer.engageResources.has('management/v1alpha1/environments/env2')).to.be.false; + }); + + it('should bulk-delete resources from a json file', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/env1', makeEnv('env1')); + engageServer.engageResources.set('management/v1alpha1/environments/env2', makeEnv('env2')); + + const { status } = await runCommand( + [ 'engage', 'delete', '--file', path.join(testDataDir, '../examples/environments.json') ], + { env: engageEnv } + ); + + expect(status).to.equal(0); + }); + + it('should handle a 400 error during bulk delete', async () => { + engageServer.engageResources.set('management/v1alpha1/environments/env2', makeEnv('env2')); + // env1 not seeded → 404 on DELETE + const { status, stderr } = await runCommand( + [ 'engage', 'delete', '--file', path.join(testDataDir, '../examples/environments.yaml') ], + { env: engageEnv } + ); + + // env1 404 should produce a non-zero exit code + expect(status).to.equal(1); + expect(stderr).to.include('not found'); + }); + }); + }); +}); diff --git a/test/commands/engage/edit/templates/edit-success.mustache b/test/commands/engage/edit/templates/edit-success.mustache new file mode 100644 index 00000000..fd15db4f --- /dev/null +++ b/test/commands/engage/edit/templates/edit-success.mustache @@ -0,0 +1 @@ +{{check}} "environment/{{string}}" has successfully been edited. diff --git a/test/commands/engage/edit/templates/help.mustache b/test/commands/engage/edit/templates/help.mustache new file mode 100644 index 00000000..dd8df747 --- /dev/null +++ b/test/commands/engage/edit/templates/help.mustache @@ -0,0 +1,5 @@ +AXWAY CLI, version {{version}} +Copyright (c) 2018-{{year}}, Axway, Inc. All Rights Reserved.{{{nodeDeprecationWarning}}} +Edit and update resources by using the default editor. + +USAGE diff --git a/test/commands/engage/edit/templates/no-changes.mustache b/test/commands/engage/edit/templates/no-changes.mustache new file mode 100644 index 00000000..c3f738a9 --- /dev/null +++ b/test/commands/engage/edit/templates/no-changes.mustache @@ -0,0 +1 @@ +{{x}} Edit cancelled, no changes made. diff --git a/test/commands/engage/edit/templates/not-authenticated.mustache b/test/commands/engage/edit/templates/not-authenticated.mustache new file mode 100644 index 00000000..b5074f74 --- /dev/null +++ b/test/commands/engage/edit/templates/not-authenticated.mustache @@ -0,0 +1 @@ +{{x}} Error: You must be authenticated diff --git a/test/commands/engage/edit/templates/not-found.mustache b/test/commands/engage/edit/templates/not-found.mustache new file mode 100644 index 00000000..9e0dbc5c --- /dev/null +++ b/test/commands/engage/edit/templates/not-found.mustache @@ -0,0 +1 @@ +Unable to retrieve Environment "{{string}}" diff --git a/test/commands/engage/edit/test-edit.js b/test/commands/engage/edit/test-edit.js new file mode 100644 index 00000000..17fdfc28 --- /dev/null +++ b/test/commands/engage/edit/test-edit.js @@ -0,0 +1,127 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; +import { runCommand, renderRegexFromFile } from '../../../helpers/index.js'; +import { + engageEnv, + setupEngageAuth, + initHomeDir, + resetHomeDir, +} from '../../../helpers/engage-test-helper.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Path to the cross-platform editor script that appends a comment so +// TmpFile detects a change (isUpdated = true). Invoked as: node