diff --git a/e2e-playwright/Dockerfile b/e2e-playwright/Dockerfile
new file mode 100644
index 000000000..470ac4456
--- /dev/null
+++ b/e2e-playwright/Dockerfile
@@ -0,0 +1,12 @@
+FROM mcr.microsoft.com/playwright:v1.52.0-jammy
+
+WORKDIR /app
+
+COPY package*.json ./
+RUN npm install
+
+COPY . .
+
+RUN npx playwright install
+
+CMD ["npm", "test"]
\ No newline at end of file
diff --git a/e2e-playwright/README.md b/e2e-playwright/README.md
new file mode 100644
index 000000000..27ad96611
--- /dev/null
+++ b/e2e-playwright/README.md
@@ -0,0 +1,56 @@
+# ๐งช kafbat-e2e-playwright
+End-to-End UI test automation using **Playwright**, **Cucumber.js**, and **TypeScript**.
+---
+
+## Prerequisites
+
+- **Node.js** >= 18
+- **npm** or **yarn**
+- Install dependencies and Playwright browsers:
+
+```bash
+Local run:
+Run kafbat (docker compose -f ./documentation/compose/e2e-tests.yaml up -d)
+npm install
+npx playwright install
+
+๐น Normal Test Run
+npm test:stage
+
+๐น Debug Mode (with Playwright Inspector)
+npm run debug
+
+๐น Rerun Failed Tests
+npm run test:failed
+
+
+Gihub action CI example
+name: CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+
+jobs:
+ container-test-job:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v3
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18
+
+ - name: Install NPM dependencies
+ run: npm install
+
+ - name: Install Playwright browsers
+ run: npx playwright install
+
+ - name: ๐ Run tests with ENV=prod
+ run: cross-env ENV=prod HEAD=false BASEURL=http://localhost:8080 npm run test
+
\ No newline at end of file
diff --git a/e2e-playwright/config/cucumber.js b/e2e-playwright/config/cucumber.js
new file mode 100644
index 000000000..57a65f79c
--- /dev/null
+++ b/e2e-playwright/config/cucumber.js
@@ -0,0 +1,51 @@
+module.exports = {
+ default: {
+ timeout: 30000,
+ tags: process.env.npm_config_TAGS || "",
+ formatOptions: {
+ snippetInterface: "async-await"
+ },
+ paths: [
+ "src/features/"
+ ],
+ publishQuiet: true,
+ dryRun: false,
+ require: [
+ "src/steps/*.ts",
+ "src/hooks/hooks.ts",
+ "src/support/customWorld.ts"
+ ],
+ requireModule: [
+ "ts-node/register"
+ ],
+ format: [
+ "progress-bar",
+ "html:test-results/cucumber-report.html",
+ "json:test-results/cucumber-report.json",
+ "rerun:@rerun.txt"
+ ],
+ parallel: 1
+ },
+ rerun: {
+ formatOptions: {
+ snippetInterface: "async-await"
+ },
+ publishQuiet: true,
+ dryRun: false,
+ require: [
+ "src/steps/*.ts",
+ "src/hooks/hooks.ts",
+ "src/support/customWorld.ts"
+ ],
+ requireModule: [
+ "ts-node/register"
+ ],
+ format: [
+ "progress-bar",
+ "html:test-results/cucumber-report.html",
+ "json:test-results/cucumber-report.json",
+ "rerun:@rerun.txt"
+ ],
+ parallel: 1
+ }
+}
\ No newline at end of file
diff --git a/e2e-playwright/package-lock.json b/e2e-playwright/package-lock.json
new file mode 100644
index 000000000..fa91bf28c
--- /dev/null
+++ b/e2e-playwright/package-lock.json
@@ -0,0 +1,2619 @@
+{
+ "name": "kafbattests",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "kafbattests",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "uuid": "^11.1.0"
+ },
+ "devDependencies": {
+ "@cucumber/cucumber": "^11.2.0",
+ "@playwright/test": "^1.52.0",
+ "@types/node": "^22.15.3",
+ "cross-env": "^7.0.3",
+ "dotenv": "^16.5.0",
+ "fs-extra": "^11.3.0",
+ "multiple-cucumber-html-reporter": "^3.9.2",
+ "ts-node": "^10.9.2",
+ "typescript": "^5.8.3",
+ "winston": "^3.17.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cucumber/ci-environment": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-10.0.1.tgz",
+ "integrity": "sha512-/+ooDMPtKSmvcPMDYnMZt4LuoipfFfHaYspStI4shqw8FyKcfQAmekz6G+QKWjQQrvM+7Hkljwx58MEwPCwwzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@cucumber/cucumber": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-11.2.0.tgz",
+ "integrity": "sha512-F69uIPTc7dfgU7/TGAaQaWUz7r/DzoPW39AfJoKQOC7IvBiPQwpvSIo6QEd+63pdpdKNRbtQoVl5vP9IclhhuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cucumber/ci-environment": "10.0.1",
+ "@cucumber/cucumber-expressions": "18.0.1",
+ "@cucumber/gherkin": "30.0.4",
+ "@cucumber/gherkin-streams": "5.0.1",
+ "@cucumber/gherkin-utils": "9.0.0",
+ "@cucumber/html-formatter": "21.7.0",
+ "@cucumber/junit-xml-formatter": "0.7.1",
+ "@cucumber/message-streams": "4.0.1",
+ "@cucumber/messages": "27.0.2",
+ "@cucumber/tag-expressions": "6.1.1",
+ "assertion-error-formatter": "^3.0.0",
+ "capital-case": "^1.0.4",
+ "chalk": "^4.1.2",
+ "cli-table3": "0.6.3",
+ "commander": "^10.0.0",
+ "debug": "^4.3.4",
+ "error-stack-parser": "^2.1.4",
+ "figures": "^3.2.0",
+ "glob": "^10.3.10",
+ "has-ansi": "^4.0.1",
+ "indent-string": "^4.0.0",
+ "is-installed-globally": "^0.4.0",
+ "is-stream": "^2.0.0",
+ "knuth-shuffle-seeded": "^1.0.6",
+ "lodash.merge": "^4.6.2",
+ "lodash.mergewith": "^4.6.2",
+ "luxon": "3.2.1",
+ "mime": "^3.0.0",
+ "mkdirp": "^2.1.5",
+ "mz": "^2.7.0",
+ "progress": "^2.0.3",
+ "read-package-up": "^11.0.0",
+ "resolve-pkg": "^2.0.0",
+ "semver": "7.5.3",
+ "string-argv": "0.3.1",
+ "supports-color": "^8.1.1",
+ "tmp": "0.2.3",
+ "type-fest": "^4.8.3",
+ "util-arity": "^1.1.0",
+ "yaml": "^2.2.2",
+ "yup": "1.2.0"
+ },
+ "bin": {
+ "cucumber-js": "bin/cucumber.js"
+ },
+ "engines": {
+ "node": "18 || 20 || 22 || >=23"
+ },
+ "funding": {
+ "url": "https://opencollective.com/cucumber"
+ }
+ },
+ "node_modules/@cucumber/cucumber-expressions": {
+ "version": "18.0.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-18.0.1.tgz",
+ "integrity": "sha512-NSid6bI+7UlgMywl5octojY5NXnxR9uq+JisjOrO52VbFsQM6gTWuQFE8syI10KnIBEdPzuEUSVEeZ0VFzRnZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "regexp-match-indices": "1.0.2"
+ }
+ },
+ "node_modules/@cucumber/gherkin": {
+ "version": "30.0.4",
+ "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-30.0.4.tgz",
+ "integrity": "sha512-pb7lmAJqweZRADTTsgnC3F5zbTh3nwOB1M83Q9ZPbUKMb3P76PzK6cTcPTJBHWy3l7isbigIv+BkDjaca6C8/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cucumber/messages": ">=19.1.4 <=26"
+ }
+ },
+ "node_modules/@cucumber/gherkin-streams": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-5.0.1.tgz",
+ "integrity": "sha512-/7VkIE/ASxIP/jd4Crlp4JHXqdNFxPGQokqWqsaCCiqBiu5qHoKMxcWNlp9njVL/n9yN4S08OmY3ZR8uC5x74Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "9.1.0",
+ "source-map-support": "0.5.21"
+ },
+ "bin": {
+ "gherkin-javascript": "bin/gherkin"
+ },
+ "peerDependencies": {
+ "@cucumber/gherkin": ">=22.0.0",
+ "@cucumber/message-streams": ">=4.0.0",
+ "@cucumber/messages": ">=17.1.1"
+ }
+ },
+ "node_modules/@cucumber/gherkin-streams/node_modules/commander": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz",
+ "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/@cucumber/gherkin-utils": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-9.0.0.tgz",
+ "integrity": "sha512-clk4q39uj7pztZuZtyI54V8lRsCUz0Y/p8XRjIeHh7ExeEztpWkp4ca9q1FjUOPfQQ8E7OgqFbqoQQXZ1Bx7fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cucumber/gherkin": "^28.0.0",
+ "@cucumber/messages": "^24.0.0",
+ "@teppeis/multimaps": "3.0.0",
+ "commander": "12.0.0",
+ "source-map-support": "^0.5.21"
+ },
+ "bin": {
+ "gherkin-utils": "bin/gherkin-utils"
+ }
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/@cucumber/gherkin": {
+ "version": "28.0.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-28.0.0.tgz",
+ "integrity": "sha512-Ee6zJQq0OmIUPdW0mSnsCsrWA2PZAELNDPICD2pLfs0Oz7RAPgj80UsD2UCtqyAhw2qAR62aqlktKUlai5zl/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cucumber/messages": ">=19.1.4 <=24"
+ }
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/@cucumber/messages": {
+ "version": "24.1.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-24.1.0.tgz",
+ "integrity": "sha512-hxVHiBurORcobhVk80I9+JkaKaNXkW6YwGOEFIh/2aO+apAN+5XJgUUWjng9NwqaQrW1sCFuawLB1AuzmBaNdQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/uuid": "9.0.8",
+ "class-transformer": "0.5.1",
+ "reflect-metadata": "0.2.1",
+ "uuid": "9.0.1"
+ }
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/@types/uuid": {
+ "version": "9.0.8",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
+ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/commander": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
+ "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/reflect-metadata": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz",
+ "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==",
+ "deprecated": "This version has a critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2 or newer.",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@cucumber/gherkin-utils/node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/@cucumber/gherkin/node_modules/@cucumber/messages": {
+ "version": "26.0.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-26.0.1.tgz",
+ "integrity": "sha512-DIxSg+ZGariumO+Lq6bn4kOUIUET83A4umrnWmidjGFl8XxkBieUZtsmNbLYgH/gnsmP07EfxxdTr0hOchV1Sg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/uuid": "10.0.0",
+ "class-transformer": "0.5.1",
+ "reflect-metadata": "0.2.2",
+ "uuid": "10.0.0"
+ }
+ },
+ "node_modules/@cucumber/gherkin/node_modules/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/@cucumber/html-formatter": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-21.7.0.tgz",
+ "integrity": "sha512-bv211aY8mErp6CdmhN426E+7KIsVIES4fGx5ASMlUzYWiMus6NhSdI9UL3Vswx8JXJMgySeIcJJKfznREUFLNA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@cucumber/messages": ">=18"
+ }
+ },
+ "node_modules/@cucumber/junit-xml-formatter": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.7.1.tgz",
+ "integrity": "sha512-AzhX+xFE/3zfoYeqkT7DNq68wAQfBcx4Dk9qS/ocXM2v5tBv6eFQ+w8zaSfsktCjYzu4oYRH/jh4USD1CYHfaQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cucumber/query": "^13.0.2",
+ "@teppeis/multimaps": "^3.0.0",
+ "luxon": "^3.5.0",
+ "xmlbuilder": "^15.1.1"
+ },
+ "peerDependencies": {
+ "@cucumber/messages": "*"
+ }
+ },
+ "node_modules/@cucumber/junit-xml-formatter/node_modules/luxon": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
+ "integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cucumber/message-streams": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-4.0.1.tgz",
+ "integrity": "sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@cucumber/messages": ">=17.1.1"
+ }
+ },
+ "node_modules/@cucumber/messages": {
+ "version": "27.0.2",
+ "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-27.0.2.tgz",
+ "integrity": "sha512-jo2B+vYXmpuLOKh6Gc8loHl2E8svCkLvEXLVgFwVHqKWZJWBTa9yTRCPmZIxrz4fnO7Pr3N3vKQCPu73/gjlVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/uuid": "10.0.0",
+ "class-transformer": "0.5.1",
+ "reflect-metadata": "0.2.2",
+ "uuid": "10.0.0"
+ }
+ },
+ "node_modules/@cucumber/messages/node_modules/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/@cucumber/query": {
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@cucumber/query/-/query-13.2.0.tgz",
+ "integrity": "sha512-S3g4u+2u/vo444bR1xL0+oVZmF8zb9QZ3MoiNF4GjBt6gG7Kf4S3NyJKjGUAQfESTb8oumOR1YMKHbv79FzA5w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@teppeis/multimaps": "3.0.0"
+ },
+ "peerDependencies": {
+ "@cucumber/messages": "*"
+ }
+ },
+ "node_modules/@cucumber/tag-expressions": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-6.1.1.tgz",
+ "integrity": "sha512-0oj5KTzf2DsR3DhL3hYeI9fP3nyKzs7TQdpl54uJelJ3W3Hlyyet2Hib+8LK7kNnqJsXENnJg9zahRYyrtvNEg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@dabh/diagnostics": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
+ "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "colorspace": "1.1.x",
+ "enabled": "2.0.x",
+ "kuler": "^2.0.0"
+ }
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@isaacs/cliui/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz",
+ "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.52.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@teppeis/multimaps": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-3.0.0.tgz",
+ "integrity": "sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "22.15.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz",
+ "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/triple-beam": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.14.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
+ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/assertion-error-formatter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz",
+ "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "diff": "^4.0.1",
+ "pad-right": "^0.2.2",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/capital-case": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz",
+ "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "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/chalk/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/class-transformer": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
+ "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cli-table3": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
+ "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": "10.* || >= 12.*"
+ },
+ "optionalDependencies": {
+ "@colors/colors": "1.5.0"
+ }
+ },
+ "node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/color/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/colorspace": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+ "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color": "^3.1.3",
+ "text-hex": "1.0.x"
+ }
+ },
+ "node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-env": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+ "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "bin": {
+ "cross-env": "src/bin/cross-env.js",
+ "cross-env-shell": "src/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=10.14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
+ "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/enabled": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/error-stack-parser": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+ "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/find": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/find/-/find-0.3.0.tgz",
+ "integrity": "sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "traverse-chain": "~0.1.0"
+ }
+ },
+ "node_modules/find-up-simple": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
+ "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fn.name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
+ "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ini": "2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-ansi": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz",
+ "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hosted-git-info": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+ "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/index-to-position": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz",
+ "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "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==",
+ "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/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/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/knuth-shuffle-seeded": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz",
+ "integrity": "sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "seed-random": "~2.2.0"
+ }
+ },
+ "node_modules/kuler": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.mergewith": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/logform": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
+ "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@colors/colors": "1.6.0",
+ "@types/triple-beam": "^1.3.2",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^2.3.1",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/logform/node_modules/@colors/colors": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/luxon": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz",
+ "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/mime": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
+ "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/multiple-cucumber-html-reporter": {
+ "version": "3.9.2",
+ "resolved": "https://registry.npmjs.org/multiple-cucumber-html-reporter/-/multiple-cucumber-html-reporter-3.9.2.tgz",
+ "integrity": "sha512-liBtbgqucEr98qNHJ2gukcjmDjREa/oyGHSRB1jVdK0pdL7cqohIzRzk0YmUVTVP8eGe7gJQ6tTHikMgudULtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find": "^0.3.0",
+ "fs-extra": "^11.3.0",
+ "jsonfile": "^6.1.0",
+ "lodash": "^4.17.21",
+ "luxon": "^3.5.0",
+ "open": "^8.4.2",
+ "uuid": "^11.0.5"
+ }
+ },
+ "node_modules/multiple-cucumber-html-reporter/node_modules/luxon": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
+ "integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/normalize-package-data": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
+ "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "hosted-git-info": "^7.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-license": "^3.0.4"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/one-time": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fn.name": "1.x.x"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/pad-right": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz",
+ "integrity": "sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "repeat-string": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
+ "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.26.2",
+ "index-to-position": "^1.1.0",
+ "type-fest": "^4.39.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/playwright": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
+ "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.52.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
+ "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/read-package-up": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
+ "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up-simple": "^1.0.0",
+ "read-pkg": "^9.0.0",
+ "type-fest": "^4.6.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
+ "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.3",
+ "normalize-package-data": "^6.0.0",
+ "parse-json": "^8.0.0",
+ "type-fest": "^4.6.0",
+ "unicorn-magic": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/reflect-metadata": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/regexp-match-indices": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz",
+ "integrity": "sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "regexp-tree": "^0.1.11"
+ }
+ },
+ "node_modules/regexp-tree": {
+ "version": "0.1.27",
+ "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+ "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "regexp-tree": "bin/regexp-tree"
+ }
+ },
+ "node_modules/repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz",
+ "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/seed-random": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz",
+ "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.5.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+ "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/spdx-correct": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+ "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+ "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+ "dev": true,
+ "license": "CC-BY-3.0"
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.21",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
+ "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/stackframe": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+ "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-argv": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi/node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/text-hex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tmp": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/traverse-chain": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
+ "integrity": "sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/triple-beam": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.0.0"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/type-fest": {
+ "version": "4.40.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz",
+ "integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unicorn-magic": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+ "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/util-arity": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz",
+ "integrity": "sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uuid": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/winston": {
+ "version": "3.17.0",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
+ "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@colors/colors": "^1.6.0",
+ "@dabh/diagnostics": "^2.0.2",
+ "async": "^3.2.3",
+ "is-stream": "^2.0.0",
+ "logform": "^2.7.0",
+ "one-time": "^1.0.0",
+ "readable-stream": "^3.4.0",
+ "safe-stable-stringify": "^2.3.1",
+ "stack-trace": "0.0.x",
+ "triple-beam": "^1.3.0",
+ "winston-transport": "^4.9.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/winston-transport": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
+ "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "logform": "^2.7.0",
+ "readable-stream": "^3.6.2",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/winston/node_modules/@colors/colors": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+ "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yup": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz",
+ "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ },
+ "node_modules/yup/node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/e2e-playwright/package.json b/e2e-playwright/package.json
new file mode 100644
index 000000000..fec2f48dd
--- /dev/null
+++ b/e2e-playwright/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "kafbat-e2e-playwright",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "debug": "cross-env ENV=stage PWDEBUG=1 DEBUG=pw:api cucumber-js --config=config/cucumber.js",
+ "pretest": "npx ts-node src/helper/report/init.ts",
+ "test": "cross-env ENV=prod FORCE_COLOR=0 cucumber-js --config=config/cucumber.js || true",
+ "test:stage": "cross-env ENV=stage FORCE_COLOR=0 cucumber-js --config=config/cucumber.js || true",
+ "posttest": "npx ts-node src/helper/report/report.ts",
+ "test:failed": "cucumber-js -p rerun @rerun.txt"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "devDependencies": {
+ "@cucumber/cucumber": "^11.2.0",
+ "@playwright/test": "^1.52.0",
+ "@types/node": "^22.15.3",
+ "cross-env": "^7.0.3",
+ "dotenv": "^16.5.0",
+ "fs-extra": "^11.3.0",
+ "multiple-cucumber-html-reporter": "^3.9.2",
+ "ts-node": "^10.9.2",
+ "typescript": "^5.8.3",
+ "winston": "^3.17.0"
+ },
+ "dependencies": {
+ "uuid": "^11.1.0"
+ }
+}
diff --git a/e2e-playwright/src/features/Topics.feature b/e2e-playwright/src/features/Topics.feature
new file mode 100644
index 000000000..03865a1cf
--- /dev/null
+++ b/e2e-playwright/src/features/Topics.feature
@@ -0,0 +1,46 @@
+Feature: Topics page visibility and functions
+
+ Scenario: Topics elements
+ Given Topics is visible
+ When click on Topics link
+ Given Topics Serchfield visible
+ And Topics ShowInternalTopics visible
+ And Topics AddATopic visible
+ And Topics DeleteSelectedTopics active is: "false"
+ And Topics CopySelectedTopic active is: "false"
+ And Topics PurgeMessagesOfSelectedTopics active is: "false"
+ When Topic SelectAllTopic visible is: "true"
+ Then Topic SelectAllTopic checked is: "true"
+ Given Topics DeleteSelectedTopics active is: "true"
+ And Topics CopySelectedTopic active is: "false"
+ And Topics PurgeMessagesOfSelectedTopics active is: "true"
+ Then Topic SelectAllTopic checked is: "false"
+ Given Topics DeleteSelectedTopics active is: "false"
+ And Topics CopySelectedTopic active is: "false"
+ And Topics PurgeMessagesOfSelectedTopics active is: "false"
+ When Topics serchfield input "SomeTopic"
+ Then Topic named: "SomeTopic" visible is: "true"
+ When Topic serchfield input cleared
+ Then Topic named: "SomeTopic" visible is: "true"
+ When Topic row named: "SomeTopic" checked is: "true"
+ Given Topics DeleteSelectedTopics active is: "true"
+ And Topics CopySelectedTopic active is: "true"
+ And Topics PurgeMessagesOfSelectedTopics active is: "true"
+ When Topic row named: "SomeTopic" checked is: "false"
+ Given Topics DeleteSelectedTopics active is: "false"
+ And Topics CopySelectedTopic active is: "false"
+ And Topics PurgeMessagesOfSelectedTopics active is: "false"
+
+ Scenario: Topics serchfield and ShowInternalTopics
+ Given Topics is visible
+ When click on Topics link
+ And Topics Serchfield visible
+ When Topics serchfield input "__consumer_offsets"
+ Then Topic named: "__consumer_offsets" visible is: "true"
+ When Topics ShowInternalTopics switched is: "false"
+ Then Topic named: "__consumer_offsets" visible is: "false"
+ When Topics ShowInternalTopics switched is: "true"
+ Then Topic named: "__consumer_offsets" visible is: "true"
+ When Topics serchfield input "SomeTopic"
+ Then Topic named: "SomeTopic" visible is: "true"
+
diff --git a/e2e-playwright/src/features/TopicsCreate.feature b/e2e-playwright/src/features/TopicsCreate.feature
new file mode 100644
index 000000000..397173163
--- /dev/null
+++ b/e2e-playwright/src/features/TopicsCreate.feature
@@ -0,0 +1,53 @@
+Feature: TopicsCreate page
+
+ Scenario: TopicCreate elemets visible
+ Given Topics is visible
+ When click on Topics link
+ Given Topics AddATopic clicked
+ Given TopicCreate heading visible is: "true"
+ Given TopicCreate TopicName input visible is: "true"
+ Given TopicCreate NumberOfPartitions input visible is: "true"
+ Given TopicCreate CleanupPolicy select visible is: "true"
+ Given TopicCreate MinInSyncReplicas input visible is: "true"
+ Given TopicCreate ReplicationFactor input visible is: "true"
+ Given TopicCreate TimeToRetainData input visible is: "true"
+ Given TopicCreate 12Hours button visible is: "true"
+ Given TopicCreate 1Day button visible is: "true"
+ Given TopicCreate 2Day button visible is: "true"
+ Given TopicCreate 7Day button visible is: "true"
+ Given TopicCreate 4Weeks button visible is: "true"
+ Given TopicCreate MaxPartitionSize select visible is: "true"
+ Given TopicCreate MaxMessageSize input visible is: "true"
+ Given TopicCreate AddCustomParameter button visible is: "true"
+ Given TopicCreate Cancel button visible is: "true"
+ Given TopicCreate CreateTopic button visible is: "true"
+
+Scenario: TopicCreate ui functions
+ Given Topics is visible
+ When click on Topics link
+ Given Topics AddATopic clicked
+ Given TopicCreate heading visible is: "true"
+ When TopicCreate Topic name starts with: "NewAutoTopic"
+ When TopicCreate Number of partitons: 2
+ When TopicCreate Time to retain data one day
+ When TopicCreate Create topic clicked
+ Then Header starts with: "NewAutoTopic"
+ When click on Topics link
+ Then Topic name started with: "NewAutoTopic" visible is: "true"
+
+Scenario: TopicCreate time to retain data functions
+ Given Topics is visible
+ When click on Topics link
+ Given Topics AddATopic clicked
+ Given TopicCreate TimeToRetainData input visible is: "true"
+ Then TopicCreate TimeToRetainData value is: ""
+ When TopicCreate 12Hours button clicked
+ Then TopicCreate TimeToRetainData value is: "43200000"
+ When TopicCreate 1Day button clicked
+ Then TopicCreate TimeToRetainData value is: "86400000"
+ When TopicCreate 2Day button clicked
+ Then TopicCreate TimeToRetainData value is: "172800000"
+ When TopicCreate 7Day button clicked
+ Then TopicCreate TimeToRetainData value is: "604800000"
+ When TopicCreate 4Weeks button clicked
+ Then TopicCreate TimeToRetainData value is: "2419200000"
\ No newline at end of file
diff --git a/e2e-playwright/src/features/navigation.feature b/e2e-playwright/src/features/navigation.feature
new file mode 100644
index 000000000..1f51ab1ff
--- /dev/null
+++ b/e2e-playwright/src/features/navigation.feature
@@ -0,0 +1,42 @@
+Feature: Navigation panel links
+
+ Scenario: Navigate to Brokers
+ Given Brokers is visible
+ When click on Brokers link
+ Then Brokers heading visible
+ Then the end of current URL should be "brokers"
+
+ Scenario: Navigate to Topics
+ Given Topics is visible
+ When click on Topics link
+ Then Topics heading visible
+ Then the part of current URL should be "topics"
+
+ Scenario: Navigate to Consumers
+ Given Consumers is visible
+ When click on Consumers link
+ Then Consumers heading visible
+ Then the end of current URL should be "consumer-groups"
+
+ Scenario: Navigate to Schema Registry
+ Given Schema Registry is visible
+ When click on Schema Registry link
+ Then Schema Registry heading visible
+ Then the end of current URL should be "schemas"
+
+ Scenario: Navigate to Kafka Connect
+ Given Kafka Connect is visible
+ When click on Kafka Connect link
+ Then Kafka Connect heading visible
+ Then the end of current URL should be "connectors"
+
+ Scenario: Navigate to KSQL DB
+ Given KSQL DB is visible
+ When click on KSQL DB link
+ Then KSQL DB heading visible
+ Then the part of current URL should be "ksqldb"
+
+ Scenario: Navigate to Dashboard
+ Given Dashboard is visible
+ When click on Dashboard link
+ Then Dashboard heading visible
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/browsers/browserManager.ts b/e2e-playwright/src/helper/browsers/browserManager.ts
new file mode 100644
index 000000000..229be1c0f
--- /dev/null
+++ b/e2e-playwright/src/helper/browsers/browserManager.ts
@@ -0,0 +1,20 @@
+import { LaunchOptions, chromium, firefox, webkit } from "@playwright/test";
+
+const options: LaunchOptions = {
+ headless: process.env.HEAD !== "true"
+}
+export const invokeBrowser = () => {
+ const browserType = process.env.npm_config_BROWSER || "chrome";
+
+ switch (browserType) {
+ case "chrome":
+ return chromium.launch(options);
+ case "firefox":
+ return firefox.launch(options);
+ case "webkit":
+ return webkit.launch(options);
+ default:
+ throw new Error("Please set the proper browser!")
+ }
+
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/env/.env.prod b/e2e-playwright/src/helper/env/.env.prod
new file mode 100644
index 000000000..890724390
--- /dev/null
+++ b/e2e-playwright/src/helper/env/.env.prod
@@ -0,0 +1,3 @@
+BASEURL = http://host.docker.internal:8080/
+BROWSER = chrome
+HEAD = false
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/env/.env.stage b/e2e-playwright/src/helper/env/.env.stage
new file mode 100644
index 000000000..671d2adeb
--- /dev/null
+++ b/e2e-playwright/src/helper/env/.env.stage
@@ -0,0 +1,3 @@
+BASEURL = http://localhost:8080/
+BROWSER = chrome
+HEAD = true
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/env/env.ts b/e2e-playwright/src/helper/env/env.ts
new file mode 100644
index 000000000..b5755b223
--- /dev/null
+++ b/e2e-playwright/src/helper/env/env.ts
@@ -0,0 +1,20 @@
+import * as dotenv from 'dotenv';
+import path from 'path';
+
+const env = process.env.ENV;
+
+if (env) {
+ const fullPath = path.resolve(`src/helper/env/.env.${env}`);
+ const result = dotenv.config({
+ override: true,
+ path: fullPath,
+ });
+
+ if (result.error) {
+ console.error(`Failed to load .env.${env} from ${fullPath}:`, result.error);
+ } else {
+ console.log(`Loaded environment variables from .env.${env}`);
+ }
+} else {
+ console.error("ENV not provided. Use ENV=dev|qa|prod in your npm script.");
+}
diff --git a/e2e-playwright/src/helper/report/init.ts b/e2e-playwright/src/helper/report/init.ts
new file mode 100644
index 000000000..2d03a58d0
--- /dev/null
+++ b/e2e-playwright/src/helper/report/init.ts
@@ -0,0 +1,8 @@
+const fs = require("fs-extra");
+try {
+ fs.ensureDir("test-results");
+ fs.emptyDir("test-results");
+
+} catch (error) {
+ console.log("Folder not created! " + error);
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/report/report.ts b/e2e-playwright/src/helper/report/report.ts
new file mode 100644
index 000000000..79cea7b18
--- /dev/null
+++ b/e2e-playwright/src/helper/report/report.ts
@@ -0,0 +1,16 @@
+const report = require("multiple-cucumber-html-reporter");
+
+report.generate({
+ jsonDir: "test-results",
+ reportPath: "test-results/reports/",
+ reportName: "Playwright Automation Report",
+ pageTitle: "report",
+ displayDuration: false,
+ customData: {
+ title: "Kafbat e2e playwright",
+ data: [
+ { label: "Release", value: "1.2.3" },
+ { label: "Cycle", value: "Smoke-1" }
+ ],
+ },
+});
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/types/env.d.ts b/e2e-playwright/src/helper/types/env.d.ts
new file mode 100644
index 000000000..fa60884f3
--- /dev/null
+++ b/e2e-playwright/src/helper/types/env.d.ts
@@ -0,0 +1,12 @@
+export { };
+
+declare global {
+ namespace NodeJS {
+ interface ProcessEnv {
+ BROWSER: "chrome" | "firefox" | "webkit",
+ ENV: "staging" | "prod" | "test",
+ BASEURL: string,
+ HEAD: "true" | "false"
+ }
+ }
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/util/logger.ts b/e2e-playwright/src/helper/util/logger.ts
new file mode 100644
index 000000000..3e65c43c9
--- /dev/null
+++ b/e2e-playwright/src/helper/util/logger.ts
@@ -0,0 +1,17 @@
+import { transports, format } from "winston";
+
+export function options(scenarioName: string) {
+ return {
+ transports: [
+ new transports.File({
+ filename: `test-results/logs/${scenarioName}/log.log`,
+ level: 'info',
+ format: format.combine(
+ format.timestamp({ format: 'MMM-DD-YYYY HH:mm:ss' }),
+ format.align(),
+ format.printf(info => `${info.level}: ${[info.timestamp]}: ${info.message}`)
+ )
+ }),
+ ]
+ }
+};
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/wrapper/PlaywrightWrappers.ts b/e2e-playwright/src/helper/wrapper/PlaywrightWrappers.ts
new file mode 100644
index 000000000..e4c420167
--- /dev/null
+++ b/e2e-playwright/src/helper/wrapper/PlaywrightWrappers.ts
@@ -0,0 +1,28 @@
+import { Page } from "@playwright/test";
+
+export default class PlaywrightWrapper {
+
+ constructor(private page: Page) { }
+
+ async goto(url: string) {
+ await this.page.goto(url, {
+ waitUntil: "domcontentloaded"
+ });
+ }
+
+ async waitAndClick(locator: string) {
+ const element = this.page.locator(locator);
+ await element.waitFor({
+ state: "visible"
+ });
+ await element.click();
+ }
+
+ async navigateTo(link: string) {
+ await Promise.all([
+ this.page.waitForNavigation(),
+ this.page.click(link)
+ ])
+ }
+
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/helper/wrapper/assert.ts b/e2e-playwright/src/helper/wrapper/assert.ts
new file mode 100644
index 000000000..544d3c824
--- /dev/null
+++ b/e2e-playwright/src/helper/wrapper/assert.ts
@@ -0,0 +1,25 @@
+import { expect, Page } from "@playwright/test";
+
+export default class Assert {
+
+ constructor(private page: Page) { }
+
+ async assertTitle(title: string) {
+ await expect(this.page).toHaveTitle(title);
+ }
+
+ async assertTitleContains(title: string) {
+ const pageTitle = await this.page.title();
+ expect(pageTitle).toContain(title);
+ }
+
+ async assertURL(url: string) {
+ await expect(this.page).toHaveURL(url);
+ }
+
+ async assertURLContains(title: string) {
+ const pageURL = this.page.url();
+ expect(pageURL).toContain(title);
+ }
+
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/hooks/hooks.ts b/e2e-playwright/src/hooks/hooks.ts
new file mode 100644
index 000000000..ee8835659
--- /dev/null
+++ b/e2e-playwright/src/hooks/hooks.ts
@@ -0,0 +1,107 @@
+import '../helper/env/env';
+import { BeforeAll, AfterAll, Before, After, Status } from "@cucumber/cucumber";
+import { Browser, BrowserContext } from "@playwright/test";
+import { fixture } from "./pageFixture";
+import { invokeBrowser } from "../helper/browsers/browserManager";
+import { createLogger } from "winston";
+import { options } from "../helper/util/logger";
+import PanelLocators from "../pages/Panel/PanelLocators";
+import BrokersLocators from "../pages/Brokers/BrokersLocators";
+import TopicsLocators from "../pages/Topics/TopicsLocators";
+import ConsumersLocators from "../pages/Consumers/ConsumersLocators";
+import SchemaRegistryLocators from "../pages/SchemaRegistry/SchemaRegistryLocators";
+import ConnectorsLocators from "../pages/Connectors/ConnectorsLocators";
+import ksqlDbLocators from "../pages/KSQLDB/ksqldbLocators";
+import DashboardLocators from '../pages/Dashboard/DashboardLocators';
+import TopicCreateLocators from "../pages/Topics/TopicsCreateLocators";
+
+let browser: Browser;
+let context: BrowserContext;
+
+BeforeAll(async function () {
+ browser = await invokeBrowser();
+
+});
+
+Before(async function ({ pickle }) {
+ const scenarioName = pickle.name + pickle.id
+ context = await browser.newContext();
+ await context.tracing.start({
+ name: scenarioName,
+ title: pickle.name,
+ sources: true,
+ screenshots: true, snapshots: true
+ });
+ const page = await context.newPage();
+
+ fixture.page = page;
+
+ fixture.logger = createLogger(options(scenarioName));
+
+ fixture.navigationPanel = new PanelLocators(page);
+
+ fixture.brokers = new BrokersLocators(page);
+
+ fixture.topics = new TopicsLocators(page);
+ fixture.topicsCreate = new TopicCreateLocators(page);
+
+ fixture.consumers = new ConsumersLocators(page);
+
+ fixture.schemaRegistry = new SchemaRegistryLocators(page);
+
+ fixture.connectors = new ConnectorsLocators(page);
+
+ fixture.ksqlDb = new ksqlDbLocators(page);
+
+ fixture.dashboard = new DashboardLocators(page);
+
+});
+
+After({ timeout: 30000 }, async function ({ pickle, result }) {
+ let img: Buffer | undefined;
+ const path = `./test-results/trace/${pickle.id}.zip`;
+
+ try {
+ if (result?.status === Status.FAILED) {
+ img = await fixture.page.screenshot({
+ path: `./test-results/screenshots/${pickle.name}.png`,
+ type: "png"
+ });
+ }
+ } catch (e) {
+ console.error("Error taking screenshot:", e);
+ }
+
+ try {
+ await context.tracing.stop({ path });
+ } catch (e) {
+ console.error("Error stopping tracing:", e);
+ }
+
+ try {
+ await fixture.page.close();
+ } catch (e) {
+ console.error("Error closing page:", e);
+ }
+
+ try {
+ await context.close();
+ } catch (e) {
+ console.error("Error closing context:", e);
+ }
+
+ try {
+ if (result?.status === Status.FAILED && img) {
+ await this.attach(img, "image/png");
+
+ const traceFileLink = `Open ${path}`;
+ await this.attach(`Trace file: ${traceFileLink}`, "text/html");
+ }
+ } catch (e) {
+ console.error("Error attaching screenshot or trace:", e);
+ }
+});
+
+AfterAll(async function () {
+ await browser.close();
+})
diff --git a/e2e-playwright/src/hooks/pageFixture.ts b/e2e-playwright/src/hooks/pageFixture.ts
new file mode 100644
index 000000000..5b6b02938
--- /dev/null
+++ b/e2e-playwright/src/hooks/pageFixture.ts
@@ -0,0 +1,45 @@
+import { Page } from "@playwright/test";
+import { Logger } from "winston";
+import PanelLocators from "../pages/Panel/PanelLocators";
+import BrokersLocators from "../pages/Brokers/BrokersLocators";
+import TopicsLocators from "../pages/Topics/TopicsLocators";
+import ConsumersLocators from "../pages/Consumers/ConsumersLocators";
+import SchemaRegistryLocators from "../pages/SchemaRegistry/SchemaRegistryLocators";
+import ConnectorsLocators from "../pages/Connectors/ConnectorsLocators";
+import ksqlDbLocators from "../pages/KSQLDB/ksqldbLocators";
+import DashboardLocators from "../pages/Dashboard/DashboardLocators";
+import TopicCreateLocators from "../pages/Topics/TopicsCreateLocators";
+
+export const fixture = {
+ // @ts-ignore
+ page: undefined as Page,
+
+ // @ts-ignore
+ logger: undefined as Logger,
+
+ // @ts-ignore
+ navigationPanel: undefined as PanelLocators,
+
+ // @ts-ignore
+ brokers: undefined as BrokersLocators,
+
+ // @ts-ignore
+ topics: undefined as TopicsLocators,
+ // @ts-ignore
+ topicsCreate: undefined as TopicCreateLocators,
+
+ // @ts-ignore
+ consumers: undefined as ConsumersLocators,
+
+ // @ts-ignore
+ schemaRegistry: undefined as SchemaRegistryLocators,
+
+ // @ts-ignore
+ connectors: undefined as ConnectorsLocators,
+
+ // @ts-ignore
+ ksqlDb: undefined as ksqlDbLocators,
+
+ // @ts-ignore
+ dashboard: undefined as DashboardLocators
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/BaseLocators.ts b/e2e-playwright/src/pages/BaseLocators.ts
new file mode 100644
index 000000000..77e290087
--- /dev/null
+++ b/e2e-playwright/src/pages/BaseLocators.ts
@@ -0,0 +1,25 @@
+import { Locator, Page } from '@playwright/test';
+
+export class BaseLocators {
+ constructor(private page: Page) {}
+
+ loadingSpinner:Locator = this.page.locator('div[role="progressbar"]');
+ submitBtn:Locator = this.page.locator('button[type="submit"]');
+ tableGrid:Locator = this.page.locator('table');
+ searchFld:Locator = this.page.locator('input[type="text"][id*=":r"]');
+ dotMenuBtn:Locator = this.page.locator('button[aria-label="Dropdown Toggle"]');
+ alertHeader:Locator = this.page.locator('div[role="alert"] div[role="heading"]');
+ alertMessage:Locator = this.page.locator('div[role="alert"] div[role="contentinfo"]');
+ confirmationMdl:Locator = this.page.locator('text=Confirm the action').locator('..');
+ confirmBtn:Locator = this.page.locator('button:has-text("Confirm")');
+ cancelBtn:Locator = this.page.locator('button:has-text("Cancel")');
+ backBtn:Locator = this.page.locator('button:has-text("Back")');
+ previousBtn:Locator = this.page.locator('button:has-text("Previous")');
+ nextBtn:Locator = this.page.locator('button:has-text("Next")');
+ ddlOptions:Locator = this.page.locator('li[value]');
+ gridItems:Locator = this.page.locator('tr[class]');
+
+ tableElementNameLocator = (name: string):Locator => this.page.locator(`tbody a:has-text("${name}")`);
+ pageTitleFromHeader = (title: string):Locator => this.page.locator(`h1:has-text("${title}")`);
+ pagePathFromHeader = (title: string):Locator => this.page.locator(`a:has-text("${title}") >> .. >> h1`);
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Brokers/BrokersLocators.ts b/e2e-playwright/src/pages/Brokers/BrokersLocators.ts
new file mode 100644
index 000000000..eddd69207
--- /dev/null
+++ b/e2e-playwright/src/pages/Brokers/BrokersLocators.ts
@@ -0,0 +1,11 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class BrokersLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ brokersHeading = (): Locator => this.page.getByRole('heading', { name: 'Brokers' });
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Connectors/ConnectorsLocators.ts b/e2e-playwright/src/pages/Connectors/ConnectorsLocators.ts
new file mode 100644
index 000000000..7a014eb73
--- /dev/null
+++ b/e2e-playwright/src/pages/Connectors/ConnectorsLocators.ts
@@ -0,0 +1,13 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class ConnectorsLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ connectorsHeading = (): Locator => this.page.getByRole('heading', { name: 'Connectors' });
+ connectorsSearchBox = (): Locator => this.page.getByRole('textbox', { name: 'SSearch by Connect Name' });
+ connectorsCreateConnectorButton = (): Locator => this.page.getByRole('button', { name: 'Create Schema' });
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Consumers/ConsumersLocators.ts b/e2e-playwright/src/pages/Consumers/ConsumersLocators.ts
new file mode 100644
index 000000000..9f4dbf379
--- /dev/null
+++ b/e2e-playwright/src/pages/Consumers/ConsumersLocators.ts
@@ -0,0 +1,13 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class ConsumersLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ consumersHeading = (): Locator => this.page.getByRole('heading', { name: 'Consumers' });
+ consumersSearchBox = (): Locator => this.page.getByRole('textbox', { name: 'Search by Consumer Group ID' });
+ consumersSearchByGroupId = (): Locator => this.page.getByText('Group ID');
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Dashboard/DashboardLocators.ts b/e2e-playwright/src/pages/Dashboard/DashboardLocators.ts
new file mode 100644
index 000000000..415e8a62c
--- /dev/null
+++ b/e2e-playwright/src/pages/Dashboard/DashboardLocators.ts
@@ -0,0 +1,11 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class DashboardLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ dashboardHeading = (): Locator => this.page.getByRole('heading', { name: 'Dashboard' });
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/KSQLDB/ksqldbLocators.ts b/e2e-playwright/src/pages/KSQLDB/ksqldbLocators.ts
new file mode 100644
index 000000000..bd98d0233
--- /dev/null
+++ b/e2e-playwright/src/pages/KSQLDB/ksqldbLocators.ts
@@ -0,0 +1,15 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class ksqlDbLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ ksqlDbHeading = (): Locator => this.page.getByRole('heading', { name: 'KSQL DB' });
+ ksqlDbExecuteKSQLREquestButton = (): Locator => this.page.getByRole('button', { name: 'Execute KSQL Request' });
+ ksqlDbTablesLink = (): Locator => this.page.getByRole('link', { name: 'Tables' });
+ ksqlDbStreamsLink = (): Locator => this.page.getByRole('link', { name: 'Streams' });
+
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Panel/PanelLocators.ts b/e2e-playwright/src/pages/Panel/PanelLocators.ts
new file mode 100644
index 000000000..05e136167
--- /dev/null
+++ b/e2e-playwright/src/pages/Panel/PanelLocators.ts
@@ -0,0 +1,20 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class PanelLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ private linkByName = (name: string): Locator =>
+ this.page.getByRole('link', { name });
+
+ brokersLink = (): Locator => this.linkByName('Brokers');
+ topicsLink = (): Locator => this.page.getByTitle('Topics');
+ consumersLink = (): Locator => this.linkByName('Consumers');
+ schemaRegistryLink = (): Locator => this.linkByName('Schema Registry');
+ ksqlDbLink = (): Locator => this.linkByName('KSQL DB');
+ getDashboardLink = (): Locator => this.linkByName('Dashboard');
+ kafkaConnectLink = (): Locator => this.linkByName('Kafka Connect');
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/SchemaRegistry/SchemaRegistryLocators.ts b/e2e-playwright/src/pages/SchemaRegistry/SchemaRegistryLocators.ts
new file mode 100644
index 000000000..438dac08e
--- /dev/null
+++ b/e2e-playwright/src/pages/SchemaRegistry/SchemaRegistryLocators.ts
@@ -0,0 +1,13 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class SchemaRegistryLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ schemaRegistryHeading = (): Locator => this.page.getByRole('heading', { name: 'Schema Registry' });
+ schemaRegistrySearchBox = (): Locator => this.page.getByRole('textbox', { name: 'Search by Schema Name' });
+ schemaRegistryCreateSchemaButton = (): Locator => this.page.getByRole('button', { name: 'Create Schema' });
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Topics/TopicsCreateLocators.ts b/e2e-playwright/src/pages/Topics/TopicsCreateLocators.ts
new file mode 100644
index 000000000..a40fff49c
--- /dev/null
+++ b/e2e-playwright/src/pages/Topics/TopicsCreateLocators.ts
@@ -0,0 +1,29 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class TopicCreateLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ topicsCreateHeading = (): Locator => this.page.getByText('TopicsCreate');
+ topicsCreateTopicName = ():Locator => this.page.getByRole('textbox', { name: 'Topic Name *' });
+ topicsCreateNumberOfPartitions = ():Locator => this.page.getByRole('spinbutton', { name: 'Number of Partitions *' });
+ topicsCreateCleanupPolicy = (): Locator => this.page.getByRole('listbox', { name: 'Cleanup policy' });
+ topicsCreateCleanupPolicySelect = (value : string): Locator => this.page.getByRole('list').getByRole('option', { name: value, exact: true });
+ topicsCreateMinInSyncReplicas = (): Locator => this.page.getByRole('spinbutton', { name: 'Min In Sync Replicas' });
+ topicsCreateReplicationFactor = (): Locator => this.page.getByRole('spinbutton', { name: 'Replication Factor' });
+ topicsCreateTimeToRetainData = (): Locator => this.page.getByRole('spinbutton', { name: 'Time to retain data (in ms)' });
+ topicsCreate12Hours = (): Locator => this.page.getByRole('button', { name: 'hours' });
+ topicsCreate1Day = (): Locator => this.page.getByRole('button', { name: '1 day' });
+ topicsCreate2Day = (): Locator => this.page.getByRole('button', { name: '2 days' });
+ topicsCreate7Day = (): Locator => this.page.getByRole('button', { name: '7 days' });
+ topicsCreate4Weeks = (): Locator => this.page.getByRole('button', { name: 'weeks' });
+ topicsCreateMaxPartitionSize = (): Locator => this.page.getByRole('listbox', { name: 'Max partition size in GB' });
+ topicsCreateMaxPartitionSizeSelect = (value: string): Locator => this.page.getByRole('option', { name: value });
+ topicsCreateMaxMessageSize = (): Locator => this.page.getByRole('spinbutton', { name: 'Maximum message size in bytes' });
+ topicsCreateAddCustomParameter = (): Locator => this.page.getByRole('button', { name: 'Add Custom Parameter' });
+ topicsCreateCancel = (): Locator => this.page.getByRole('button', { name: 'Cancel' });
+ topicCreateCreateTopicButton = (): Locator => this.page.getByRole('button', { name: 'Create topic' });
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/pages/Topics/TopicsLocators.ts b/e2e-playwright/src/pages/Topics/TopicsLocators.ts
new file mode 100644
index 000000000..a38fe37bc
--- /dev/null
+++ b/e2e-playwright/src/pages/Topics/TopicsLocators.ts
@@ -0,0 +1,22 @@
+import { Page, Locator } from "@playwright/test";
+
+export default class TopicsLocators{
+ private readonly page: Page;
+
+ constructor(page: Page) {
+ this.page = page;
+ }
+
+ topicsHeading = (): Locator => this.page.getByRole("heading", { name: "Topics" });
+ topicSearchField = (): Locator => this.page.getByRole('textbox', { name: 'Search by Topic Name' });
+ topicSearchFieldCleanText = (): Locator => this.page.getByRole('button').filter({ hasText: /^$/ }).locator('path');
+ topicShowInternalTopics = (): Locator => this.page.locator('label').filter({ hasText: 'Show Internal Topics' }).locator('span');
+ topicAddTopicButton = (): Locator => this.page.getByRole('button', { name: 'Add a Topic' });
+ topicSelectAllCheckbox = (): Locator => this.page.getByRole('row', { name: 'Topic Name Partitions Out of' }).getByRole('checkbox');
+ topicDeleteSelectedTopicsButton = (): Locator => this.page.getByRole('button', { name: 'Delete selected topics' });
+ topicCopySelectedTopicButton = (): Locator => this.page.getByRole('button', { name: 'Copy selected topic' });
+ topicPurgeMessagesOfSelectedTopicsButton = (): Locator => this.page.getByRole('button', { name: 'Purge messages of selected' });
+ topicSelectAllCheckBox = (): Locator => this.page.getByRole('row', { name: 'Topic Name Partitions Out of' }).getByRole('checkbox');
+ topicRowCheckBox = (message:string): Locator => this.page.getByRole('row', { name: message }).getByRole('checkbox');
+ topicNameLink = (value:string) : Locator => this.page.getByRole('link', { name: value })
+}
\ No newline at end of file
diff --git a/e2e-playwright/src/services/commonFunctions.ts b/e2e-playwright/src/services/commonFunctions.ts
new file mode 100644
index 000000000..359cf40af
--- /dev/null
+++ b/e2e-playwright/src/services/commonFunctions.ts
@@ -0,0 +1,6 @@
+import { v4 as uuidv4 } from 'uuid';
+import { Locator} from '@playwright/test';
+
+export const generateName = (prefix: string): string => {
+ return `${prefix}-${uuidv4().slice(0, 8)}`;
+};
diff --git a/e2e-playwright/src/services/uiHelper.ts b/e2e-playwright/src/services/uiHelper.ts
new file mode 100644
index 000000000..0064b55c9
--- /dev/null
+++ b/e2e-playwright/src/services/uiHelper.ts
@@ -0,0 +1,22 @@
+import { expect, Locator } from '@playwright/test';
+
+export const expectVisibility = async (locator: Locator, visibleString: string): Promise => {
+ if (visibleString === "true") {
+ await expect(locator).toBeVisible();
+ } else {
+ await expect(locator).toHaveCount(0);
+ }
+};
+
+export const ensureCheckboxState = async (checkbox: Locator, expectedState: string) => {
+ const desiredState = expectedState === 'true';
+ const isChecked = await checkbox.isChecked();
+
+ if (isChecked !== desiredState) {
+ if (desiredState) {
+ await checkbox.check();
+ } else {
+ await checkbox.uncheck();
+ }
+ }
+};
\ No newline at end of file
diff --git a/e2e-playwright/src/steps/Topics.steps.ts b/e2e-playwright/src/steps/Topics.steps.ts
new file mode 100644
index 000000000..442103eda
--- /dev/null
+++ b/e2e-playwright/src/steps/Topics.steps.ts
@@ -0,0 +1,86 @@
+import { Given, When, Then, setDefaultTimeout } from "@cucumber/cucumber";
+import { expect } from "@playwright/test";
+import { fixture } from "../hooks/pageFixture";
+import { expectVisibility, ensureCheckboxState } from "../services/uiHelper";
+
+setDefaultTimeout(60 * 1000 * 2);
+
+Given('Topics Serchfield visible', async () => {
+ await expect(fixture.topics.topicSearchField()).toBeVisible();
+});
+
+Given('Topics ShowInternalTopics visible', async () => {
+ await expect(fixture.topics.topicShowInternalTopics()).toBeVisible();
+});
+
+
+Given('Topics AddATopic visible', async () => {
+ await expect(fixture.topics.topicAddTopicButton()).toBeVisible();
+});
+
+
+Given('Topics DeleteSelectedTopics active is: {string}', async (state: string) => {
+ const isEnabled = await fixture.topics.topicDeleteSelectedTopicsButton().isEnabled();
+
+ expect(isEnabled.toString()).toBe(state);
+});
+
+
+Given('Topics CopySelectedTopic active is: {string}', async (state: string) => {
+ const isEnabled = await fixture.topics.topicCopySelectedTopicButton().isEnabled();
+
+ expect(isEnabled.toString()).toBe(state);
+});
+
+
+Given('Topics PurgeMessagesOfSelectedTopics active is: {string}', async (state: string) => {
+ const isEnabled = await fixture.topics.topicPurgeMessagesOfSelectedTopicsButton().isEnabled();
+
+ expect(isEnabled.toString()).toBe(state);
+});
+
+When('Topic SelectAllTopic visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topics.topicSelectAllCheckBox(), visible)
+});
+
+
+Then('Topic SelectAllTopic checked is: {string}', async (state: string) => {
+ const checkbox = fixture.topics.topicSelectAllCheckBox();
+ await ensureCheckboxState(checkbox, state);
+ const actual = await checkbox.isChecked();
+ expect(actual.toString()).toBe(state);
+});
+
+When('Topics serchfield input {string}', async (topicName: string) => {
+ const textBox = fixture.topics.topicSearchField();
+
+ await textBox.fill(topicName);
+
+ const actual = await textBox.inputValue();
+ expect(actual, topicName)
+});
+
+Then('Topic named: {string} visible is: {string}', async (topicName: string, visible: string) => {
+ await expectVisibility(fixture.topics.topicNameLink(topicName), visible);
+});
+
+When('Topic serchfield input cleared', async () => {
+ const textBox = fixture.topics.topicSearchField();
+
+ await textBox.fill('');
+
+ const text = await textBox.inputValue();
+ expect(text).toBe('');
+});
+
+When('Topics ShowInternalTopics switched is: {string}', async (state: string) => {
+ const checkBox = fixture.topics.topicShowInternalTopics();
+
+ await ensureCheckboxState(checkBox, state);
+});
+
+When('Topic row named: {string} checked is: {string}', async (topicName: string, state: string) => {
+ const checkbox = fixture.topics.topicRowCheckBox(topicName);
+
+ await ensureCheckboxState(checkbox, state);
+});
diff --git a/e2e-playwright/src/steps/TopicsCreate.steps.ts b/e2e-playwright/src/steps/TopicsCreate.steps.ts
new file mode 100644
index 000000000..137774725
--- /dev/null
+++ b/e2e-playwright/src/steps/TopicsCreate.steps.ts
@@ -0,0 +1,143 @@
+import { Given, When, Then, setDefaultTimeout } from "@cucumber/cucumber";
+import { expect } from "@playwright/test";
+import { fixture } from "../hooks/pageFixture";
+import { expectVisibility } from "../services/uiHelper";
+import { CustomWorld } from "../support/customWorld";
+import { generateName } from "../services/commonFunctions";
+
+setDefaultTimeout(60 * 1000 * 2);
+
+
+Given('Topics AddATopic clicked', async () => {
+ const button = fixture.topics.topicAddTopicButton();
+ await expect(button).toBeVisible();
+ await button.click();
+});
+
+Given('TopicCreate heading visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateHeading(), visible);
+});
+
+Given('TopicCreate TopicName input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateTopicName(), visible);
+});
+
+Given('TopicCreate NumberOfPartitions input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateNumberOfPartitions(), visible);
+});
+
+Given('TopicCreate CleanupPolicy select visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateCleanupPolicy(), visible);
+});
+
+Given('TopicCreate MinInSyncReplicas input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateMinInSyncReplicas(), visible);
+});
+
+Given('TopicCreate ReplicationFactor input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateReplicationFactor(), visible);
+});
+
+Given('TopicCreate TimeToRetainData input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateTimeToRetainData(), visible);
+});
+
+Given('TopicCreate 12Hours button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreate12Hours(), visible);
+});
+
+Given('TopicCreate 1Day button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreate1Day(), visible);
+});
+
+Given('TopicCreate 2Day button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreate2Day(), visible);
+});
+
+Given('TopicCreate 7Day button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreate7Day(), visible);
+});
+
+Given('TopicCreate 4Weeks button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreate4Weeks(), visible);
+});
+
+Given('TopicCreate MaxPartitionSize select visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateMaxPartitionSize(), visible);
+});
+
+Given('TopicCreate MaxMessageSize input visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateMaxMessageSize(), visible);
+});
+
+Given('TopicCreate AddCustomParameter button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateAddCustomParameter(), visible);
+});
+
+Given('TopicCreate Cancel button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicsCreateCancel(), visible);
+});
+
+Given('TopicCreate CreateTopic button visible is: {string}', async (visible: string) => {
+ await expectVisibility(fixture.topicsCreate.topicCreateCreateTopicButton(), visible);
+});
+
+
+When('TopicCreate Topic name starts with: {string}', async function (this: CustomWorld, prefix: string) {
+ const topicName = generateName(prefix);
+ this.setValue(`topicName-${prefix}`, topicName);
+ await fixture.topicsCreate.topicsCreateTopicName().fill(topicName);
+});
+
+When('TopicCreate Number of partitons: {int}', async function (this: CustomWorld, count: number) {
+ const input = fixture.topicsCreate.topicsCreateNumberOfPartitions();
+ await input.fill(count.toString());
+});
+
+When('TopicCreate Time to retain data one day', async function (this: CustomWorld) {
+ const button = fixture.topicsCreate.topicsCreate1Day();
+ await button.click();
+});
+
+When('TopicCreate Create topic clicked', async function (this: CustomWorld) {
+ const button = fixture.topicsCreate.topicCreateCreateTopicButton();
+ await button.click();
+});
+
+Then('Header starts with: {string}', async function (this: CustomWorld, prefix: string) {
+ const topicName = this.getValue(`topicName-${prefix}`);
+ const header = fixture.page.getByRole('heading', { name: topicName });
+
+ await expect(header).toBeVisible();
+});
+
+Then('Topic name started with: {string} visible is: {string}', async function (this: CustomWorld, prefix: string, visible: string) {
+ const topicName = this.getValue(`topicName-${prefix}`);
+ await expectVisibility(fixture.topics.topicNameLink(topicName), visible);
+});
+
+Then('TopicCreate TimeToRetainData value is: {string}', async (expectedValue: string) => {
+ const input = fixture.topicsCreate.topicsCreateTimeToRetainData();
+ const actualValue = await input.inputValue();
+ expect(actualValue).toBe(expectedValue);
+});
+
+When('TopicCreate 12Hours button clicked', async () => {
+ await fixture.topicsCreate.topicsCreate12Hours().click();
+});
+
+When('TopicCreate 1Day button clicked', async () => {
+ await fixture.topicsCreate.topicsCreate1Day().click();
+});
+
+When('TopicCreate 2Day button clicked', async () => {
+ await fixture.topicsCreate.topicsCreate2Day().click();
+});
+
+When('TopicCreate 7Day button clicked', async () => {
+ await fixture.topicsCreate.topicsCreate7Day().click();
+});
+
+When('TopicCreate 4Weeks button clicked', async () => {
+ await fixture.topicsCreate.topicsCreate4Weeks().click();
+});
\ No newline at end of file
diff --git a/e2e-playwright/src/steps/navigation.steps.ts b/e2e-playwright/src/steps/navigation.steps.ts
new file mode 100644
index 000000000..0a3bbbf82
--- /dev/null
+++ b/e2e-playwright/src/steps/navigation.steps.ts
@@ -0,0 +1,115 @@
+import { Given, When, Then, setDefaultTimeout } from "@cucumber/cucumber";
+import { expect } from "@playwright/test";
+import { fixture } from "../hooks/pageFixture";
+
+setDefaultTimeout(60 * 1000 * 2);
+
+Given('Brokers is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.brokersLink()).toBeVisible();
+ });
+
+When('click on Brokers link', async () => {
+ await fixture.navigationPanel.brokersLink().click();
+});
+
+Then('Brokers heading visible', async () => {
+ await fixture.brokers.brokersHeading().waitFor({ state: 'visible' });
+});
+
+
+Given('Topics is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.topicsLink()).toBeVisible();
+});
+
+When('click on Topics link', async () => {
+ await fixture.navigationPanel.topicsLink().click();
+});
+
+Then('Topics heading visible', async () => {
+ await fixture.topics.topicsHeading().waitFor({ state: 'visible' });
+});
+
+
+Given('Consumers is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.consumersLink()).toBeVisible();
+});
+
+When('click on Consumers link', async () => {
+ await fixture.navigationPanel.consumersLink().click();
+});
+
+Then('Consumers heading visible', async () => {
+ await fixture.consumers.consumersHeading().waitFor({ state: 'visible' });
+});
+
+
+Given('Schema Registry is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.schemaRegistryLink()).toBeVisible();
+});
+
+When('click on Schema Registry link', async () => {
+ await fixture.navigationPanel.schemaRegistryLink().click();
+});
+
+Then('Schema Registry heading visible', async () => {
+ await fixture.schemaRegistry.schemaRegistryHeading().waitFor({ state: 'visible' });
+});
+
+
+Given('Kafka Connect is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.kafkaConnectLink()).toBeVisible();
+});
+
+When('click on Kafka Connect link', async () => {
+ await fixture.navigationPanel.kafkaConnectLink().click();
+});
+
+Then('Kafka Connect heading visible', async () => {
+ await fixture.connectors.connectorsHeading().waitFor({ state: 'visible' });
+});
+
+Given('KSQL DB is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ await expect(fixture.navigationPanel.ksqlDbLink()).toBeVisible();
+});
+
+When('click on KSQL DB link', async () => {
+ await fixture.navigationPanel.ksqlDbLink().click();
+});
+
+Then('KSQL DB heading visible', async () => {
+ await fixture.ksqlDb.ksqlDbHeading().waitFor({ state: 'visible' });
+});
+
+
+Given('Dashboard is visible', async () => {
+ await fixture.page.goto(process.env.BASEURL!);
+ var tmp = fixture.navigationPanel.getDashboardLink();
+ await expect(fixture.navigationPanel.getDashboardLink()).toBeVisible();
+});
+
+When('click on Dashboard link', async () => {
+ const dashboard = fixture.navigationPanel.getDashboardLink()
+ await dashboard.isVisible();
+ await dashboard.click();
+});
+
+Then('Dashboard heading visible', async () => {
+ await fixture.dashboard.dashboardHeading().waitFor({ state: 'visible' });
+});
+
+
+Then('the end of current URL should be {string}', async (expected: string) => {
+ const actual = new URL(fixture.page.url()).pathname;
+ expect(actual.endsWith(expected)).toBeTruthy();
+});
+
+Then('the part of current URL should be {string}', async (expected: string) => {
+ const actual = new URL(fixture.page.url()).pathname;
+ expect(actual.includes(expected)).toBeTruthy();
+ });
diff --git a/e2e-playwright/src/support/customWorld.ts b/e2e-playwright/src/support/customWorld.ts
new file mode 100644
index 000000000..764623bcb
--- /dev/null
+++ b/e2e-playwright/src/support/customWorld.ts
@@ -0,0 +1,25 @@
+import { IWorldOptions, setWorldConstructor, World } from '@cucumber/cucumber';
+
+export class CustomWorld extends World {
+ private context: Map = new Map();
+
+ constructor(options: IWorldOptions) {
+ super(options);
+ }
+
+ setValue(key: string, value: any) {
+ this.context.set(key, value);
+ }
+
+ getValue(key: string): T {
+ const value = this.context.get(key);
+ if (value === undefined) throw new Error(`Key '${key}' not found in context.`);
+ return value as T;
+ }
+
+ clear() {
+ this.context.clear();
+ }
+}
+
+setWorldConstructor(CustomWorld);
\ No newline at end of file
diff --git a/e2e-playwright/tsconfig.json b/e2e-playwright/tsconfig.json
new file mode 100644
index 000000000..264092083
--- /dev/null
+++ b/e2e-playwright/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "CommonJS",
+ "strict": true,
+ "esModuleInterop": true,
+ "moduleResolution": "node",
+ "skipLibCheck": true,
+ "resolveJsonModule": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "sourceMap": true
+ },
+ "include": ["src/**/*.ts", "src/steps/**/*.ts", "src/features/**/*.ts"]
+ }
\ No newline at end of file