diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index d1a4ca6..2374685 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,7 +4,7 @@ name: Publish to NPM on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + - "v[0-9]+.[0-9]+.[0-9]+" permissions: contents: read @@ -20,7 +20,7 @@ jobs: - name: checkout uses: actions/checkout@v6 with: - fetch-depth: 0 # Fetch full history for branch verification + fetch-depth: 0 # Fetch full history for branch verification - name: verify tag is on main branch run: | @@ -33,8 +33,8 @@ jobs: - name: setup node uses: actions/setup-node@v6 with: - node-version: '20' - registry-url: 'https://registry.npmjs.org' + node-version: 22.x + registry-url: "https://registry.npmjs.org" - name: build and publish run: | diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..b1cfe32 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,80 @@ +name: Release + +on: + push: + branches: [main, next, next-setup] +permissions: + id-token: write + contents: write + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: ["22.x", "24.x", "26.x"] + + name: Test on Node ${{ matrix.node-version }} + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Set up Docker + uses: docker/setup-buildx-action@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Run integration tests + env: + SKIP_TEARDOWN: false + REUSE_CONTAINER: false + NODE_ENV: test + FUSIONAUTH_TELEMETRY: false + run: npm test + timeout-minutes: 15 + + release: + name: Release + needs: test + runs-on: ubuntu-latest + defaults: + run: + shell: /usr/bin/bash -l -e -o pipefail {0} + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 22.x + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Install semantic-release extra plugins + run: npm install --save-dev @semantic-release/changelog @semantic-release/git + + # - name: Lint + # run: npm run lint-fix + + - name: Build + run: npm run build + + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx semantic-release diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/test.yaml similarity index 54% rename from .github/workflows/integration-tests.yml rename to .github/workflows/test.yaml index 208a6b9..44a5aad 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/test.yaml @@ -1,34 +1,42 @@ -name: Integration Tests +name: Tests on: + push: + pull_request: workflow_dispatch: jobs: - integration-tests: + test: runs-on: ubuntu-latest - + strategy: + fail-fast: false + matrix: + node-version: ["22.x", "24.x", "26.x"] + + name: Test on Node ${{ matrix.node-version }} steps: - - uses: actions/checkout@v6 - + - name: Checkout + uses: actions/checkout@v7 + - name: Set up Docker uses: docker/setup-buildx-action@v4 - - - name: Setup Node.js + + - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: - node-version: '22' - + node-version: ${{ matrix.node-version }} + - name: Install dependencies - run: npm install - + run: npm ci + - name: Build run: npm run build - + - name: Run integration tests env: SKIP_TEARDOWN: false REUSE_CONTAINER: false NODE_ENV: test FUSIONAUTH_TELEMETRY: false - run: npm run test + run: npm test timeout-minutes: 15 diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..70bd3dd --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no-install commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..e69de29 diff --git a/.npmrc b/.npmrc index 7e26447..9555e17 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1 @@ tag-version-prefix="" -min-release-age=7 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0c03f9d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,44 @@ +## [1.9.1-next-setup.2](https://github.com/FusionAuth/fusionauth-node-cli/compare/v1.9.1-next-setup.1...v1.9.1-next-setup.2) (2026-07-09) + + +### Bug Fixes + +* **release:** adds dependency of test job ([3cd41cf](https://github.com/FusionAuth/fusionauth-node-cli/commit/3cd41cf2465965658abb6d07ce5e116da402fedd)) + +## [1.9.1-next-setup.1](https://github.com/FusionAuth/fusionauth-node-cli/compare/v1.9.0...v1.9.1-next-setup.1) (2026-07-09) + + +### Bug Fixes + +* **release:** adds back github token ([cd34c52](https://github.com/FusionAuth/fusionauth-node-cli/commit/cd34c52382950ebea18dc6a6e07f68fb8b5e0697)) +* **release:** adds defaults ([fdac965](https://github.com/FusionAuth/fusionauth-node-cli/commit/fdac965d591b21a657fb105285b6c0898322c387)) +* **release:** adds permissions to action ([d66921b](https://github.com/FusionAuth/fusionauth-node-cli/commit/d66921ba6c2289bdeacb9388c2d1b48ec474845d)) +* **release:** brings testing job into release action ([94551bd](https://github.com/FusionAuth/fusionauth-node-cli/commit/94551bdce7c7baafaae59c615b8e375329b122f5)) +* **release:** fixes commitlint issues ([ac51e58](https://github.com/FusionAuth/fusionauth-node-cli/commit/ac51e588f5c879c2580f1fa0ade6c7ccfed20884)) +* **release:** fixes typo in workflow ([53d1443](https://github.com/FusionAuth/fusionauth-node-cli/commit/53d1443b34cd24e177f9fd8964741519a6352de8)) +* **release:** makes release config common js ([ccefcad](https://github.com/FusionAuth/fusionauth-node-cli/commit/ccefcad70568436994732baedbb21d4c4fabeb5d)) +* **release:** removes extraneous test that was causing failure in build not local ([687bbd6](https://github.com/FusionAuth/fusionauth-node-cli/commit/687bbd6e766909aae65f5f50a550449c514f0c58)) +* **release:** removes PR action and corrects branch for testing push ([5a1059a](https://github.com/FusionAuth/fusionauth-node-cli/commit/5a1059a0c36313b2ba5c713288735f89973faee6)) +* **release:** replaces inline testing with test workflow chaining ([d5b77b7](https://github.com/FusionAuth/fusionauth-node-cli/commit/d5b77b7326925295e50ac3606194033c27e70e76)) +* **release:** stop committing build output and drop unused deps ([d64ac2c](https://github.com/FusionAuth/fusionauth-node-cli/commit/d64ac2c3b37c3a260e3f9e5f31464a2b873a8bfd)), closes [#45](https://github.com/FusionAuth/fusionauth-node-cli/issues/45) +* **release:** updates branches for workflow for main and next ([725d29c](https://github.com/FusionAuth/fusionauth-node-cli/commit/725d29c4216a3729c0d010cdcebf3b73aae508b9)) +* **release:** updates workflow away from quotations as per the github docs ([c6dbd1a](https://github.com/FusionAuth/fusionauth-node-cli/commit/c6dbd1a53ac9ad1d22cd11256446c9893a8ea132)) + +## [1.8.3-next-setup.2](https://github.com/FusionAuth/fusionauth-node-cli/compare/v1.8.3-next-setup.1...v1.8.3-next-setup.2) (2026-07-08) + + +### Bug Fixes + +* **release:** stop committing build output and drop unused deps ([d64ac2c](https://github.com/FusionAuth/fusionauth-node-cli/commit/d64ac2c3b37c3a260e3f9e5f31464a2b873a8bfd)), closes [#45](https://github.com/FusionAuth/fusionauth-node-cli/issues/45) + +## [1.8.3-next-setup.1](https://github.com/FusionAuth/fusionauth-node-cli/compare/v1.8.2...v1.8.3-next-setup.1) (2026-07-08) + + +### Bug Fixes + +* **release:** adds back github token ([cd34c52](https://github.com/FusionAuth/fusionauth-node-cli/commit/cd34c52382950ebea18dc6a6e07f68fb8b5e0697)) +* **release:** adds defaults ([fdac965](https://github.com/FusionAuth/fusionauth-node-cli/commit/fdac965d591b21a657fb105285b6c0898322c387)) +* **release:** adds permissions to action ([d66921b](https://github.com/FusionAuth/fusionauth-node-cli/commit/d66921ba6c2289bdeacb9388c2d1b48ec474845d)) +* **release:** fixes commitlint issues ([ac51e58](https://github.com/FusionAuth/fusionauth-node-cli/commit/ac51e588f5c879c2580f1fa0ade6c7ccfed20884)) +* **release:** makes release config common js ([ccefcad](https://github.com/FusionAuth/fusionauth-node-cli/commit/ccefcad70568436994732baedbb21d4c4fabeb5d)) +* **release:** removes PR action and corrects branch for testing push ([5a1059a](https://github.com/FusionAuth/fusionauth-node-cli/commit/5a1059a0c36313b2ba5c713288735f89973faee6)) diff --git a/README.md b/README.md index 884cffe..17e2de9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The FusionAuth CLI is a command line tool for interacting with FusionAuth. It is ## Requirements -* A modern version of node (tested on 19, 20 and 22) +* A supported LTS version of Node.js — 22.22.0 or newer (tested in CI on 22, 24 and 26) * A FusionAuth instance (download it here: https://fusionauth.io/download) ## Installation & usage @@ -24,6 +24,8 @@ fusionauth --help; Currently, the CLI supports the following commands: - Common config check - `fusionauth check:common-config` - Checks to make sure common configuration settings are set. +- OAuth 2.1 compliance check + - `fusionauth check:oauth-2-1` - Checks FusionAuth configuration for OAuth 2.1 compliance. - Emails - `fusionauth email:download` - Download a specific template or all email templates from a FusionAuth server. - `fusionauth email:duplicate` - Duplicate an email template locally. @@ -123,12 +125,71 @@ npm run build; npx fusionauth -h; ``` +To run commands directly from source during development (without installing globally): +```bash +npm run build && node dist/index.js [options] + +# Example: +node dist/index.js check:oauth-2-1 --key --host http://localhost:9011 +``` + To see examples of use: https://fusionauth.io/docs/extend/code/lambdas/testing ## Troubleshooting If you run this multiple times in a row against a local instance, the number of admin users may be incorrect until you re-index. See [this issue for more](https://github.com/FusionAuth/fusionauth-issues/issues/3271). -## License +## OAuth 2.1 Compliance + +The `check:oauth-2-1` command validates your FusionAuth instance against OAuth 2.1 specification requirements ([draft-ietf-oauth-v2-1-15](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15)). + +### Usage + +```bash +# Check all applications across all tenants +fusionauth check:oauth-2-1 --key --host + +# Check a specific application +fusionauth check:oauth-2-1 --key --host --application-id + +# Check all applications in a specific tenant +fusionauth check:oauth-2-1 --key --host --tenant-id + +# Enforce strict mode (fail on deprecated grants) +fusionauth check:oauth-2-1 --key --host --strict + +# Output as JSON +fusionauth check:oauth-2-1 --key --host --json + +# Show verbose per-application breakdown +fusionauth check:oauth-2-1 --key --host --verbose +``` + +### What It Checks + +Only applications with both the `authorization_code` and `refresh_token` grants enabled are checked. + +**REQUIRED (causes exit 1 if failed):** +- PKCE enforcement set to "Required" on all applications (§7.5) +- Redirect URI validation set to "ExactMatch" — no wildcards (§4.1.3) +- HTTPS enforcement for all redirect URIs except localhost (§1.5) +- Refresh token rotation enabled via "OneTimeUse" usage policy (§4.3) +- Refresh token revocation on one-time token reuse enabled at the tenant level (§4.3) +- Tenant issuer properly configured — not default "acme.com" + +**WARNINGS (informational, does not cause exit 1):** +- DPoP (sender-constrained tokens) available for applications (§1.4.3) +- Authorization code lifetime ≤ 600 seconds (§7.5) +- No deprecated grants enabled — Implicit, Password (§10); use `--strict` to make this a failure + +### Known FusionAuth OAuth 2.1 Limitations + +FusionAuth does not fully implement all OAuth 2.1 security requirements. The following gaps exist: + +1. **Missing `iss` authorization response parameter** ([§7.14](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15#section-7.14)) + The `iss` authorization response parameter for mix-up mitigation doesn't appear to be supported — use distinct redirect URIs per authorization server as a workaround (§7.14.2). See [fusionauth-issues#1383](https://github.com/FusionAuth/fusionauth-issues/issues/1383). -This code is available as open source under the terms of the [Apache v2.0 License](https://opensource.org/licenses/Apache-2.0). +For more information: +- [OAuth 2.1 Specification (draft-ietf-oauth-v2-1-15)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15) +- [FusionAuth OAuth Configuration](https://fusionauth.io/docs/apis/applications) +- [FusionAuth Tenant Configuration](https://fusionauth.io/docs/apis/tenants) diff --git a/__tests__/telemetry/index.js b/__tests__/telemetry/index.js index 82e4942..a56d1f2 100644 --- a/__tests__/telemetry/index.js +++ b/__tests__/telemetry/index.js @@ -11,12 +11,12 @@ import nock from 'nock' export function telemetry() { const mockedTrueConfig = { - id: '8c0a77f2-27e4-4284-b5d3-5618ec2a56eb', + id: '8c0a77f2-27e4-4284-b5d3-5618ec2a56eb', telemetry: true, version: '1.0' } const mockedFalseConfig = { - id: '8c0a77f2-27e4-4284-b5d3-5618ec2a56eb', + id: '8c0a77f2-27e4-4284-b5d3-5618ec2a56eb', telemetry: false, version: '1.0' } diff --git a/__tests__/telemetry/telemetry.test.js b/__tests__/telemetry/telemetry.test.js index 479f218..d562f94 100644 --- a/__tests__/telemetry/telemetry.test.js +++ b/__tests__/telemetry/telemetry.test.js @@ -100,20 +100,6 @@ describe('telemetry runs properly', () => { delete process.env.FUSIONAUTH_TELEMETRY } }) - - test("If FUSIONAUTH_TELEMETRY === true DO run", async () => { - process.env.FUSIONAUTH_TELEMETRY = 'true' - nock('https://us.i.posthog.com') - .post('/batch/') - .reply(200) - try { - const response = await logEvent('test event') - assert.equal(response, true, "logEvent didn't fire") - } finally { - nock.cleanAll() - delete process.env.FUSIONAUTH_TELEMETRY - } - }) test("If no .env, event submits", async () => { nock('https://us.i.posthog.com') .post('/batch/') diff --git a/package-lock.json b/package-lock.json index 5f6ec05..252d350 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,77 +1,379 @@ { "name": "@fusionauth/cli", - "version": "1.8.4", + "version": "1.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@fusionauth/cli", - "version": "1.8.4", + "version": "1.9.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@comandeer/cli-spinner": "^1.0.2", - "@commander-js/extra-typings": "11.0.0", - "@faker-js/faker": "^8.4.1", - "@fusionauth/typescript-client": "1.47.0", + "@commander-js/extra-typings": "15.0.0", + "@faker-js/faker": "^10.5.0", + "@fusionauth/typescript-client": "1.68.0", "bcryptjs": "^3.0.3", "boxen": "^8.0.1", - "chalk": "5.3.0", - "chokidar": "3.5.3", - "command-exists": "^1.2.9", - "commander": "11.0.0", + "chalk": "5.6.2", + "chokidar": "5.0.0", + "commander": "15.0.0", "dotenv": "^17.4.2", - "figlet": "1.6.0", - "fs-extra": "11.1.1", - "html-to-text": "9.0.5", - "inquirer": "^13.3.0", - "log-symbols": "5.1.0", - "log-update": "5.0.1", + "figlet": "1.11.0", + "fs-extra": "11.3.6", + "html-to-text": "10.0.0", + "inquirer": "^14.0.2", + "log-symbols": "7.0.1", + "log-update": "8.0.0", "merge": "2.1.1", - "posthog-node": "^5.21.2", + "posthog-node": "^5.40.0", "queue": "7.0.0", - "remove-undefined-objects": "3.0.0", - "uuid": "9.0.0", - "yocto-spinner": "^1.1.0" + "remove-undefined-objects": "9.0.0", + "uuid": "14.0.1", + "yocto-spinner": "^1.2.1" }, "bin": { "fusionauth": "dist/index.js" }, "devDependencies": { - "@types/figlet": "1.5.6", - "@types/fs-extra": "11.0.1", - "@types/html-to-text": "9.0.1", + "@commitlint/cli": "21.2.1", + "@commitlint/config-conventional": "21.2.0", + "@types/figlet": "1.7.0", + "@types/fs-extra": "11.0.4", + "@types/html-to-text": "9.0.4", "@types/mock-fs": "^4.13.4", - "@types/node": "20.4.5", - "@types/uuid": "9.0.2", + "@types/node": "26.1.1", + "husky": "^9.1.7", "mock-fs": "^5.5.0", - "nock": "^14.0.15", - "tsx": "^4.19.4", - "type-fest": "3.13.0", - "typescript": "5.1.6" + "nock": "^14.0.16", + "tsx": "^4.23.0", + "type-fest": "5.8.0", + "typescript": "7.0.2" + }, + "engines": { + "node": ">=22.22.0" } }, - "node_modules/@comandeer/cli-spinner": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@comandeer/cli-spinner/-/cli-spinner-1.0.2.tgz", - "integrity": "sha512-rdUXcb/Vu3cSwdciv2wYHYP322nM7tAOgSVJmEvtQknKy6eysCy8PiFUyvBWW/CXV20PIkPD9hTVPXIFhfEwew==", + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^6.2.0", - "is-interactive": "^2.0.0", - "tslib": "^2.6.1" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, "node_modules/@commander-js/extra-typings": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-11.0.0.tgz", - "integrity": "sha512-06ol6Kn5gPjFY6v0vWOZ84nQwyqhZdaeZCHYH3vhwewjpOEjniF1KHZxh18887G3poWiJ8qyq5pb6ANuiddfPQ==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.1.tgz", + "integrity": "sha512-blsZGe29hJ72VGEFVl72IVYX+1vsfINpjA9yWQA6i7OKD/McGEOXg08sKIRKjFk4JvzhV/9n0l3i6NooPLTNfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-conventional": "^21.2.0", + "@commitlint/format": "^21.2.0", + "@commitlint/lint": "^21.2.0", + "@commitlint/load": "^21.2.0", + "@commitlint/read": "^21.2.1", + "@commitlint/types": "^21.2.0", + "tinyexec": "^1.0.0", + "yargs": "^18.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.2.0.tgz", + "integrity": "sha512-Qf8WRDVcyVd14if6VTWenebxFbKnVnbzPUJjlzjkyJGeHK2xCGd63Dr1XZzj0plXKQb9P0BfOxoc1HVeCo2BWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "conventional-changelog-conventionalcommits": "^10.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.0.tgz", + "integrity": "sha512-t7AzNHAKeIdo/3NRGwzpufKHsKkPHmFs/56N2Fnsh0/r0rGtnQzTxk6vnFgjaGr4hdSQKNB50/KAhR9Yk4LJKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/ensure": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.0.tgz", + "integrity": "sha512-76IF9vDNS13lAzEEik9eKwzt8f9hYhWiwVXZ2AnyLCz5/f511FsEQ3pw1X3/zSQpdRLQU7i5qDMVKyXi1GWjSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "es-toolkit": "^1.46.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-21.0.1.tgz", + "integrity": "sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/format": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.0.tgz", + "integrity": "sha512-c4q64xaav2U83t7k7RyzJerBZurPer7FxUOY0RL5L/6CZijZ7K+s6HIBGIghj0ey1P2+seRX0J9XQYtDued6tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.0.tgz", + "integrity": "sha512-4/eB0vBN7L88O/oC4ajAEqi7j2ZfNgxl/+11RfAV9YosejZgDXhY2C9VcHnHJhOzPLoSy5P3Mg/46kqeyJfXKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/lint": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.0.tgz", + "integrity": "sha512-ceO5dp9pLjEZ6y6qbq/uXWXDPykqqlTsyzoQ0NzecpisSJhK3kTy9qzQoPeJuWG/IMNdV1lO0RgmzqoAlSi1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^21.2.0", + "@commitlint/parse": "^21.2.0", + "@commitlint/rules": "^21.2.0", + "@commitlint/types": "^21.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/load": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.0.tgz", + "integrity": "sha512-RjlzWQqruRwIenJEfZtq7kG97co97nKoHpflE5YnF61tDLXxHPrdWImgzw6VL6MlFyaOcVlk74eBV8ZQmc3oIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.2.0", + "@commitlint/execute-rule": "^21.0.1", + "@commitlint/resolve-extends": "^21.2.0", + "@commitlint/types": "^21.2.0", + "cosmiconfig": "^9.0.1", + "cosmiconfig-typescript-loader": "^6.1.0", + "es-toolkit": "^1.46.0", + "is-plain-obj": "^4.1.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/message": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-21.2.0.tgz", + "integrity": "sha512-YxGoiXD/HXNXLJPrQwE5poXa+XH0CBEm+mdvbHQP0g6MV/dmJyUFCzPNzZbxL93GvZ70TmtTK0Z0/IBpAqHv8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/parse": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.0.tgz", + "integrity": "sha512-QHWxG4d0PLTF634/AdyZ0MQS+CLn5YOuJlCFhMMlSGKFxzYGUetkHBj18xgBD+6fVzUrA2lrCdi/vlS2f/oYXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.2.0", + "conventional-changelog-angular": "^9.0.0", + "conventional-commits-parser": "^7.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/read": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.1.tgz", + "integrity": "sha512-hUW7EJQnNTL0vPOmVMNK4CrnrNBN0nN+JJHReFkdHO5y4iyHeEmTBwuC15OCqUTjxWo7idnH1LftfpWVIaPWIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^21.2.0", + "@commitlint/types": "^21.2.0", + "@conventional-changelog/git-client": "^3.0.0", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.0.tgz", + "integrity": "sha512-4O/1j51+79Wth9s/MGxt/5gs0XYLDgNlYpltQfhAvLE0itusLKs9zruxbiNg1oOkmkb9L9L4USYGjEj7n87NxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.2.0", + "@commitlint/types": "^21.2.0", + "es-toolkit": "^1.46.0", + "global-directory": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/rules": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.0.tgz", + "integrity": "sha512-C2yXMNpiB8ETZKfx5JD8+ExgF8vTU1VQMKPSUUYwqKpw9oJWQBrlXBpdU038mj2WPjof7o9UzFpmTyBeGMZwZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^21.2.0", + "@commitlint/message": "^21.2.0", + "@commitlint/to-lines": "^21.0.1", + "@commitlint/types": "^21.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-21.0.1.tgz", + "integrity": "sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/top-level": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-21.2.0.tgz", + "integrity": "sha512-Y5gmQ+KxzqCrBFJfLvFEPvvwD3LDiNZoTT2yeFBm96M8qhmqSzQc5DvX3rheAaAMjyIvMXOCLS/mWfdpONsjyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/types": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.0.tgz", + "integrity": "sha512-7zVFCDB2reMvJH5dmbKnOQPjZEvjdJTH8jc0U/PIPU1r3/+vf5pD1HlfitV2MWsWXrvu7u39iY1lyLUPOaN0Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-parser": "^7.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@conventional-changelog/git-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.0.tgz", + "integrity": "sha512-Tqa/gHco2WJWa740NRjOrfKVvzIqxkZpecb8bemaQ8sKM5PXb1UK4uTyTb/1wIqNuOVaDOFxyBdhTIQZn6gdjQ==", + "dev": true, "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^2.0.0", + "@simple-libs/stream-utils": "^2.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=22" + }, "peerDependencies": { - "commander": "11.0.x" + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.0.1" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, + "node_modules/@conventional-changelog/template": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.2.1.tgz", + "integrity": "sha512-TzlTVpKPjaqW6qOYjQcYUDuGsLCNsvFHVBXkYGTAnf5V37jCWrE5haKNXzz0WZUtVHjrpV76L1buANjwXMfT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" } }, "node_modules/@esbuild/aix-ppc64": { @@ -517,9 +819,9 @@ } }, "node_modules/@faker-js/faker": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", - "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.5.0.tgz", + "integrity": "sha512-bsxD8WLS5lIj7aaoCx1YJkktqYj5vlBUE6HWzu2Q51ksrGJ0H737ECCKlFU7Yf8Br45z9t99frBp/J7kzbMPAg==", "funding": [ { "type": "opencollective", @@ -528,14 +830,14 @@ ], "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0", - "npm": ">=6.14.13" + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" } }, "node_modules/@fusionauth/typescript-client": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@fusionauth/typescript-client/-/typescript-client-1.47.0.tgz", - "integrity": "sha512-XXBy5BnoTED5HScxtxgbHEO3neIkTocEo9AUVDprk3JER49BbZbaNoMHrbMioJNAM5LWs3AN8AHIot18oq96nA==", + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/@fusionauth/typescript-client/-/typescript-client-1.68.0.tgz", + "integrity": "sha512-sologxFpdf8CzRj5xSwhaAoKQUdL8fflBSkqA+vskmyZQ5l1a52cSkeZq+wD3YQWZsAM61tNG9WR8zNihMbFeQ==", "license": "Apache-2.0", "dependencies": { "node-fetch": "^2.6.1" @@ -913,38 +1215,76 @@ "license": "MIT" }, "node_modules/@posthog/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.10.0.tgz", - "integrity": "sha512-Xk3JQ+cdychsvftrV3G9ZrN9W329lbyFW0pGJXFGKFQf8qr4upw2SgNg9BVorjSrfhoXZRnJGt/uNF4nGFBL5A==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.39.6.tgz", + "integrity": "sha512-o6ajIwN5zXoNP0D4H/QPmOyibNTUkSyOR6ya7AG5U2ywXx4awo72L2KnCoiZPQM5x/bXv6jPBdimH8M18Ax0aw==", "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6" + "@posthog/types": "^1.392.0" } }, + "node_modules/@posthog/types": { + "version": "1.392.1", + "resolved": "https://registry.npmjs.org/@posthog/types/-/types-1.392.1.tgz", + "integrity": "sha512-Qg6Gl7/1vlr8+gPtBi5gwnLgAgiyFoKOVmTvTtDcvya9cpTwZfna7rQmkGQ4B63CunUYNNbOlqcwiUwUDyTK6w==", + "license": "MIT" + }, "node_modules/@selderee/plugin-htmlparser2": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", - "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.12.0.tgz", + "integrity": "sha512-oELmoyA6ML9jDRMV3kgcMQFKxUfBU0yFVn6yTctVaLT5ygXnxH52I3TZEgV9EhXJC68/uFvE5Daj1/25c0Xa/A==", "license": "MIT", "dependencies": { - "domhandler": "^5.0.3", - "selderee": "^0.11.0" + "domelementtype": "~2.3.0", + "domhandler": "~5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" + }, + "peerDependencies": { + "selderee": "~0.12.0" + } + }, + "node_modules/@simple-libs/child-process-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz", + "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^2.0.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz", + "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" }, "funding": { - "url": "https://ko-fi.com/killymxi" + "url": "https://ko-fi.com/dangreen" } }, "node_modules/@types/figlet": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@types/figlet/-/figlet-1.5.6.tgz", - "integrity": "sha512-AOdn9cKJGXpqfHeif16xeGMwWefB4nsOyxkdRMpc+PEP3nUxzu3psJfIqhjrCNW4Sejt5i6rISWmEwK0sw03mA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-KwrT7p/8Eo3Op/HBSIwGXOsTZKYiM9NpWRBJ5sVjWP/SmlS+oxxRvJht/FNAtliJvja44N3ul1yATgohnVBV0Q==", "dev": true, "license": "MIT" }, "node_modules/@types/fs-extra": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", - "integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -953,9 +1293,9 @@ } }, "node_modules/@types/html-to-text": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-9.0.1.tgz", - "integrity": "sha512-sHu702QGb0SP2F0Zt+CxdCmGZIZ0gEaaCjqOh/V4iba1wTxPVntEPOM/vHm5bel08TILhB3+OxUTkDJWnr/zHQ==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-9.0.4.tgz", + "integrity": "sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==", "dev": true, "license": "MIT" }, @@ -980,85 +1320,441 @@ } }, "node_modules/@types/node": { - "version": "20.4.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", - "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", + "version": "26.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", + "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/uuid": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", - "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.1.0" + "undici-types": "~8.3.0" } }, - "node_modules/ansi-align/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==", - "license": "MIT", + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/ansi-align/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==", - "license": "MIT" - }, - "node_modules/ansi-align/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==", - "license": "MIT", + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/ansi-align/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==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/ansi-align/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==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/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==", + "license": "MIT" + }, + "node_modules/ansi-align/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/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==", + "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/ansi-align/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==", "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=14.16" + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1088,18 +1784,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" }, "node_modules/bcryptjs": { "version": "3.0.3", @@ -1110,18 +1800,6 @@ "bcrypt": "bin/bcrypt" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/boxen": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", @@ -1156,16 +1834,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, "node_modules/camelcase": { @@ -1181,9 +1857,9 @@ } }, "node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -1199,30 +1875,18 @@ "license": "MIT" }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 20.19.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/cli-boxes": { @@ -1238,15 +1902,15 @@ } }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "license": "MIT", "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1261,42 +1925,125 @@ "node": ">= 12" } }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "license": "MIT" + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } }, "node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=22.12.0" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.2.1.tgz", + "integrity": "sha512-oWSL6ZhnXbYraOFTK3PgRAQJ8fADDAEv5K6AdeyQPLvjFmhG8+ejL0jZZp/R7vTmGJaBvZEE+sE7dB4bCv7sAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@conventional-changelog/template": "^1.2.1" + }, + "engines": { + "node": ">=22" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/conventional-changelog-conventionalcommits": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-10.2.1.tgz", + "integrity": "sha512-n4Kr1HFMTf3iMbES0TMxKIcYtUUv4rKqyQQp2JwfOEfFCOfGT3Tq4mCyJ8S9/YPyWhydjfKrrvnyl+gCjA+mJQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@conventional-changelog/template": "^1.2.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/conventional-commits-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.0.1.tgz", + "integrity": "sha512-6VtskFpPsNkGVk/TY2RnV/MEdKfvCPBtQZN9x8jh9+k5RWBQ+tiaWn5UFCzTr0Dd88iKx7xghxbjBRp5uIzp3g==", + "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@simple-libs/stream-utils": "^2.0.0", + "meow": "^14.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">= 8" + "node": ">=22" } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" } }, "node_modules/dom-serializer": { @@ -1366,12 +2113,6 @@ "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==", - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", @@ -1390,6 +2131,49 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", @@ -1432,6 +2216,23 @@ "@esbuild/win32-x64": "0.28.1" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -1447,6 +2248,23 @@ "fast-string-truncated-width": "^3.0.2" } }, + "node_modules/fast-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-wrap-ansi": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", @@ -1457,33 +2275,33 @@ } }, "node_modules/figlet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.6.0.tgz", - "integrity": "sha512-31EQGhCEITv6+hi2ORRPyn3bulaV9Fl4xOdR169cBzH/n1UqcxsiSB/noo6SJdD7Kfb1Ljit+IgR1USvF/XbdA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.11.0.tgz", + "integrity": "sha512-EEx3OS/l2bFqcUNN2NM9FPJp8vAMrgbCxsbl2hbcJNNxOEwVe3mEzrhan7TbJQViZa8mMqhihlbCaqD+LyYKTQ==", "license": "MIT", + "dependencies": { + "commander": "^14.0.0" + }, "bin": { "figlet": "bin/index.js" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 17.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/figlet/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=20" } }, "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -1498,6 +2316,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1508,6 +2327,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", @@ -1520,16 +2349,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", + "node_modules/global-directory": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", + "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "ini": "6.0.0" }, "engines": { - "node": ">= 6" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { @@ -1539,25 +2372,28 @@ "license": "ISC" }, "node_modules/html-to-text": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", - "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-10.0.0.tgz", + "integrity": "sha512-2OH59Gtprdczel+7Rxgpz9hGVJREaf8Lt1H4kZwWHpEn70VQKRuMNGsb2eDbwaTzrYzb0hheiOG1P7Dim0B4dQ==", "license": "MIT", "dependencies": { - "@selderee/plugin-htmlparser2": "^0.11.0", - "deepmerge": "^4.3.1", + "@selderee/plugin-htmlparser2": "~0.12.0", + "deepmerge-ts": "^7.1.5", "dom-serializer": "^2.0.0", - "htmlparser2": "^8.0.2", - "selderee": "^0.11.0" + "htmlparser2": "^10.1.0", + "selderee": "~0.12.0" }, "engines": { - "node": ">=14" + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/KillyMXI" } }, "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -1569,8 +2405,36 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" } }, "node_modules/iconv-lite": { @@ -1589,84 +2453,85 @@ "url": "https://opencollective.com/express" } }, - "node_modules/inquirer": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-13.4.3.tgz", - "integrity": "sha512-EPd3IqieHSavSOXh+LZhrIkdQcOELWeRblLT6kslQr+cF9XTh/HxZdSt1YkHH1iq4dvqBnV42uwg2YlorgOy6g==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.5", - "@inquirer/core": "^11.1.10", - "@inquirer/prompts": "^8.4.3", - "@inquirer/type": "^4.0.5", - "mute-stream": "^3.0.0", - "run-async": "^4.0.6", - "rxjs": "^7.8.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" + "node": ">=6" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "license": "MIT", + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/inquirer": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-14.0.2.tgz", + "integrity": "sha512-VsSx1JneSNp3ld1veMTLe+UDcUD8Tw2/jjOthhkX3/IX2q+xHhVELifeb/hsb1fBw31pabEPNUf/xUOyb+KZjA==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/prompts": "^8.5.2", + "@inquirer/type": "^4.0.7", + "mute-stream": "^3.0.0", + "run-async": "^4.0.6" }, "engines": { - "node": ">=0.10.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1679,32 +2544,84 @@ "dev": true, "license": "MIT" }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -1726,114 +2643,101 @@ } }, "node_modules/leac": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", - "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.7.0.tgz", + "integrity": "sha512-qMrZeyEekgdRQ9o6a4NAB2EQZrv827GJdn1vnapwSJ90hWRB4TzUSunvacPkxQ2TnNqHNI1/zSt0hlo0crG8Jw==", "license": "MIT", "funding": { - "url": "https://ko-fi.com/killymxi" + "url": "https://github.com/sponsors/KillyMXI" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", "license": "MIT", "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-8.0.0.tgz", + "integrity": "sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==", "license": "MIT", "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" + "ansi-escapes": "^7.3.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^9.0.0", + "string-width": "^8.2.0", + "strip-ansi": "^7.2.0", + "wrap-ansi": "^10.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=22" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "node_modules/log-update/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", "license": "MIT", "dependencies": { - "type-fest": "^1.0.2" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/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==", - "license": "MIT" - }, - "node_modules/log-update/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==", + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" + "node": ">=20" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/log-update/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==", + "node_modules/meow": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", + "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/merge": { @@ -1842,13 +2746,16 @@ "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "license": "MIT" }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mock-fs": { @@ -1905,25 +2812,16 @@ } } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1936,59 +2834,85 @@ "dev": true, "license": "MIT" }, - "node_modules/parseley": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", - "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { - "leac": "^0.6.0", - "peberminta": "^0.9.0" + "callsites": "^3.0.0" }, - "funding": { - "url": "https://ko-fi.com/killymxi" + "engines": { + "node": ">=6" } }, - "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==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/peberminta": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", - "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "node_modules/parseley": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.13.1.tgz", + "integrity": "sha512-uNBJZzmb60l6p6VWLTmevizNAGnE0xoSf1n0B4q3ntegDNzcS68NRCcBDZTcyXHxt2XhBChsCuqj4M+nChvE/A==", "license": "MIT", + "dependencies": { + "leac": "^0.7.0", + "peberminta": "^0.10.0" + }, "funding": { - "url": "https://ko-fi.com/killymxi" + "url": "https://github.com/sponsors/KillyMXI" } }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "node_modules/peberminta": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.10.0.tgz", + "integrity": "sha512-80B2AsU+I4Qdb0ZAPSfe9UwvGzwkM37IKIFEvdS3D/3Ndgv2bsuJ0bfG1+iEYO+l7Gfd4EUJmuRyq7efLgRMzQ==", "license": "MIT", - "engines": { - "node": ">=8.6" - }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/KillyMXI" } }, + "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/posthog-node": { - "version": "5.21.2", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.21.2.tgz", - "integrity": "sha512-Jehlu0KguL1LLyUczCt86OtA5INmeStK3zcgbv1BSyMcNxs0HP3GQogBrYhwhqHsk6JopiFFVpJyZEoXOUMhGw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.40.0.tgz", + "integrity": "sha512-DrLfHuauO0W6qruF80iqr5JdmLysef74XzOB4eh36oRLRhxCySLraTqsi2Pj161LZnp9/JNdRDxwT8ei8VK2YA==", "license": "MIT", "dependencies": { - "@posthog/core": "1.10.0" + "@posthog/core": "^1.39.6" }, "engines": { - "node": ">=20" + "node": "^20.20.0 || >=22.22.0" + }, + "peerDependencies": { + "rxjs": "^7.0.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } } }, "node_modules/propagate": { @@ -2008,48 +2932,63 @@ "license": "MIT" }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/remove-undefined-objects": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-undefined-objects/-/remove-undefined-objects-3.0.0.tgz", - "integrity": "sha512-nxG1yYfc/Jxi+bNCBiqKhxVJPE+QvziIOKbD+Dxc93Uisz92v/ZYpo4WR0TJuf+dk2xE8lW2WPJsA3mDFzXy8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remove-undefined-objects/-/remove-undefined-objects-9.0.0.tgz", + "integrity": "sha512-oTxi32KwkldmtDNo5IshRJBrCs8Pq6mB4F3Cc+Ehqh0kMExH3lONr8SoTkAD5An7ZGlu6ljus89gz2qp9bfzXQ==", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=22" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, "node_modules/run-async": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", @@ -2059,15 +2998,6 @@ "node": ">=0.12.0" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2075,36 +3005,28 @@ "license": "MIT" }, "node_modules/selderee": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", - "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.12.0.tgz", + "integrity": "sha512-b1YMh3+DHZp59DLna3qVwQ5iOla/nrI6mLBNW02XxU77M3046Df6VLkoaJyFz20VsGIG5kkp+FK0kg4K4HnUFw==", "license": "MIT", "dependencies": { - "parseley": "^0.12.0" + "parseley": "~0.13.1" }, "funding": { - "url": "https://ko-fi.com/killymxi" + "url": "https://github.com/sponsors/KillyMXI" } }, - "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==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "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==", - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/signal-exit": { @@ -2120,16 +3042,16 @@ } }, "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz", + "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==", "license": "MIT", "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=12" + "node": ">=22" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -2174,16 +3096,27 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "dev": true, "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" + "engines": { + "node": ">=20" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=18" } }, "node_modules/tr46": { @@ -2192,12 +3125,6 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, - "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==", - "license": "0BSD" - }, "node_modules/tsx": { "version": "4.23.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", @@ -2218,31 +3145,62 @@ } }, "node_modules/type-fest": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.0.tgz", - "integrity": "sha512-Gur3yQGM9qiLNs0KPP7LPgeRbio2QTt4xXouobMCarR0/wyW3F+F/+OWwshg3NG0Adon7uQfSZBpB46NfhoF1A==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", + "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", "dev": true, "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" - } + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "devOptional": true, + "license": "MIT" }, "node_modules/universalify": { "version": "2.0.1", @@ -2254,13 +3212,16 @@ } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/webidl-conversions": { @@ -2279,21 +3240,6 @@ "webidl-conversions": "^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==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/widest-line": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", @@ -2326,6 +3272,44 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, "node_modules/yocto-spinner": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.1.tgz", diff --git a/package.json b/package.json index dab5caf..bd605d5 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "1.9.0", "description": "FusionAuth CLI", "main": "dist/index.js", + "engines": { + "node": ">=22.22.0" + }, "files": [ "dist", "resources/*" @@ -12,10 +15,9 @@ "copy-files": "cp -r ./src/resources/ ./dist/commands/resources/", "prepublishOnly": "npm run build", "postinstall": "test -f dist/postinstall.js && node dist/postinstall.js || true", - "start": "node --import=tsx src/index.ts", - "test": "NODE_ENV=test node --import=tsx --test __tests__/postInstall/postinstall.test.js __tests__/telemetry/telemetry.test.js __tests__/utilities/kickstart/validator.test.js __tests__/utilities/kickstart/variable-substitution.test.js __tests__/integration/apply/apply.integration.test.js", - "test:integration": "NODE_ENV=test node --import=tsx --test __tests__/integration/apply/apply.integration.test.js", - "test:unit": "NODE_ENV=test node --import=tsx --test __tests__/postInstall/postinstall.test.js __tests__/telemetry/telemetry.test.js __tests__/utilities/kickstart/validator.test.js __tests__/utilities/kickstart/variable-substitution.test.js" + "start": "npm run build && node dist/index.js", + "test": "node --import tsx --test", + "prepare": "husky" }, "keywords": [ "fusionauth", @@ -34,45 +36,50 @@ }, "homepage": "https://github.com/FusionAuth/fusionauth-node-cli#readme", "dependencies": { - "@comandeer/cli-spinner": "^1.0.2", - "@commander-js/extra-typings": "11.0.0", - "@faker-js/faker": "^8.4.1", - "@fusionauth/typescript-client": "1.47.0", + "@commander-js/extra-typings": "15.0.0", + "@faker-js/faker": "^10.5.0", + "@fusionauth/typescript-client": "1.68.0", "bcryptjs": "^3.0.3", "boxen": "^8.0.1", - "chalk": "5.3.0", - "chokidar": "3.5.3", - "command-exists": "^1.2.9", - "commander": "11.0.0", + "chalk": "5.6.2", + "chokidar": "5.0.0", + "commander": "15.0.0", "dotenv": "^17.4.2", - "figlet": "1.6.0", - "fs-extra": "11.1.1", - "html-to-text": "9.0.5", - "inquirer": "^13.3.0", - "log-symbols": "5.1.0", - "log-update": "5.0.1", + "figlet": "1.11.0", + "fs-extra": "11.3.6", + "html-to-text": "10.0.0", + "inquirer": "^14.0.2", + "log-symbols": "7.0.1", + "log-update": "8.0.0", "merge": "2.1.1", - "posthog-node": "^5.21.2", + "posthog-node": "^5.40.0", "queue": "7.0.0", - "remove-undefined-objects": "3.0.0", - "uuid": "9.0.0", - "yocto-spinner": "^1.1.0" + "remove-undefined-objects": "9.0.0", + "uuid": "14.0.1", + "yocto-spinner": "^1.2.1" }, "devDependencies": { - "@types/figlet": "1.5.6", - "@types/fs-extra": "11.0.1", - "@types/html-to-text": "9.0.1", + "@commitlint/cli": "21.2.1", + "@commitlint/config-conventional": "21.2.0", + "@types/figlet": "1.7.0", + "@types/fs-extra": "11.0.4", + "@types/html-to-text": "9.0.4", "@types/mock-fs": "^4.13.4", - "@types/node": "20.4.5", - "@types/uuid": "9.0.2", - "tsx": "^4.19.4", + "@types/node": "26.1.1", + "husky": "^9.1.7", "mock-fs": "^5.5.0", - "nock": "^14.0.15", - "type-fest": "3.13.0", - "typescript": "5.1.6" + "nock": "^14.0.16", + "tsx": "^4.23.0", + "type-fest": "5.8.0", + "typescript": "7.0.2" }, "bin": { "fusionauth": "dist/index.js" }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, "type": "module" } diff --git a/release.config.cjs b/release.config.cjs new file mode 100644 index 0000000..477c946 --- /dev/null +++ b/release.config.cjs @@ -0,0 +1,32 @@ +module.exports = { + branches: [ + 'main', + { + name: 'next', + prerelease: true + }, + { + name: 'next-setup', + prerelease: true + } + ], + plugins: [ + '@semantic-release/commit-analyzer', + '@semantic-release/release-notes-generator', + [ + '@semantic-release/changelog', + { + changelogFile: 'CHANGELOG.md' + } + ], + '@semantic-release/npm', + '@semantic-release/github', + [ + '@semantic-release/git', + { + assets: ['CHANGELOG.md'], + message: 'chore(release): set `package.json` to ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}' + } + ] + ] +} \ No newline at end of file diff --git a/src/commands/check-oauth-2-1.ts b/src/commands/check-oauth-2-1.ts new file mode 100644 index 0000000..6565931 --- /dev/null +++ b/src/commands/check-oauth-2-1.ts @@ -0,0 +1,826 @@ +import {Command, Option} from "@commander-js/extra-typings"; +import { + Application, + FusionAuthClient, + GrantType, + Oauth2AuthorizedURLValidationPolicy, + ProofKeyForCodeExchangePolicy, + ReactorFeatureStatus, + RefreshTokenUsagePolicy, + Tenant, +} from '@fusionauth/typescript-client'; +import chalk from "chalk"; +import {errorAndExit, logEvent} from '../utils.js'; +import {apiKeyOption, hostOption} from "../options.js"; + +// -- Types ------------------------------------------------------------------- + +type CheckSeverity = 'required' | 'warning'; + +interface CheckResult { + name: string; + passed: boolean; + severity: CheckSeverity; + message: string; + details?: string[]; + specSection?: string; + specUrl?: string; +} + +interface AppCheckContext { + app: Application; + appName: string; + appId: string; +} + +interface JsonOutput { + compliant: boolean; + tenantsChecked: number; + applicationsChecked: number; + applicationsSkipped: number; + filters: { + tenantId: string | null; + applicationId: string | null; + }; + checks: Record; + criticalIssues: string[]; + warnings: string[]; + educationalLinks: Record; +} + +// -- Options ----------------------------------------------------------------- + +const applicationIdOption = new Option( + '--application-id ', + 'Check a specific application only' +); + +const tenantIdOption = new Option( + '--tenant-id ', + 'Check all applications in a specific tenant' +); + +const strictOption = new Option( + '--strict', + 'Fail if deprecated grants (Implicit or Password) are enabled' +).default(false); + +const jsonOption = new Option( + '--json', + 'Output results as JSON' +).default(false); + +const verboseOption = new Option( + '--verbose', + 'Show detailed per-application breakdown' +).default(false); + +// -- Helpers ----------------------------------------------------------------- + +const SPEC_BASE = 'https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15'; + +/** Well-known fixed ID of the FusionAuth admin UI application. */ +const FUSIONAUTH_APP_ID = '3c219e58-ed0e-4b18-ad48-f4f92793ae32'; + +/** Immutable role ID for the Tenant Manager 'admin' role. */ +const TENANT_MANAGER_ADMIN_ROLE_ID = '631ecd9d-8d40-4c13-8277-80cedb823714'; + +function specUrl(section: string): string { + return `${SPEC_BASE}#section-${section}`; +} + +function isLocalhostUri(uri: string): boolean { + try { + const url = new URL(uri); + return url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1'; + } catch { + return false; + } +} + +/** + * Detect built-in FusionAuth applications that are not under the developer's + * control and should be excluded from all OAuth 2.1 checks. + * + * - FusionAuth admin UI: identified by its fixed well-known application ID. + * - Tenant Manager: identified by the combination of being a universal + * application, having a single redirect of "/tenant-manager", and containing + * a role with the immutable ID 631ecd9d-8d40-4c13-8277-80cedb823714 named + * "admin". + */ +function isBuiltInApplication(app: Application): boolean { + // FusionAuth admin UI + if (app.id === FUSIONAUTH_APP_ID) { + return true; + } + + // Tenant Manager — universal application with specific redirect and role + if (app.universalConfiguration?.universal !== true) { + return false; + } + + const redirects = app.oauthConfiguration?.authorizedRedirectURLs || []; + if (redirects.length !== 1 || redirects[0] !== '/tenant-manager') { + return false; + } + + const hasAdminRole = app.roles?.some( + r => r.id === TENANT_MANAGER_ADMIN_ROLE_ID && r.name === 'admin' + ) ?? false; + + return hasAdminRole; +} + +function shouldCheckApplication(app: Application): boolean { + if (isBuiltInApplication(app)) { + return false; + } + const grants = app.oauthConfiguration?.enabledGrants || []; + return grants.includes(GrantType.authorization_code) && grants.includes(GrantType.refresh_token); +} + +function getAppName(app: Application): string { + return app.name || 'Unnamed Application'; +} + +function getAppId(app: Application): string { + return app.id || 'unknown'; +} + +// -- Individual Checks ------------------------------------------------------- + +function checkPkce(ctx: AppCheckContext): CheckResult | null { + const policy = ctx.app.oauthConfiguration?.proofKeyForCodeExchangePolicy; + if (policy === ProofKeyForCodeExchangePolicy.Required) { + return null; // pass + } + return { + name: 'pkce', + passed: false, + severity: 'required', + message: `Application "${ctx.appName}" (${ctx.appId}): PKCE policy is "${policy || 'not set'}" (must be "Required")`, + specSection: '7.5', + specUrl: specUrl('7.5'), + }; +} + +function checkRedirectUriValidation(ctx: AppCheckContext): CheckResult | null { + const policy = ctx.app.oauthConfiguration?.authorizedURLValidationPolicy; + if (policy === Oauth2AuthorizedURLValidationPolicy.ExactMatch) { + return null; // pass + } + return { + name: 'redirectUriValidation', + passed: false, + severity: 'required', + message: `Application "${ctx.appName}" (${ctx.appId}): Redirect URI validation is "${policy || 'not set'}" (must be "ExactMatch")`, + specSection: '4.1.3', + specUrl: specUrl('4.1.3'), + }; +} + +function checkHttpsEnforcement(ctx: AppCheckContext): CheckResult[] { + const redirectUris = ctx.app.oauthConfiguration?.authorizedRedirectURLs || []; + const failures: CheckResult[] = []; + + for (const uri of redirectUris) { + if (uri.startsWith('https://')) { + continue; + } + if (isLocalhostUri(uri)) { + continue; + } + failures.push({ + name: 'httpsEnforcement', + passed: false, + severity: 'required', + message: `Application "${ctx.appName}" (${ctx.appId}): Non-HTTPS redirect URI: ${uri}`, + specSection: '1.5', + specUrl: specUrl('1.5'), + }); + } + return failures; +} + +function checkRefreshTokenRotation(ctx: AppCheckContext): CheckResult | null { + const policy = ctx.app.jwtConfiguration?.refreshTokenUsagePolicy; + if (policy === RefreshTokenUsagePolicy.OneTimeUse) { + return null; // pass + } + return { + name: 'refreshTokenRotation', + passed: false, + severity: 'required', + message: `Application "${ctx.appName}" (${ctx.appId}): Refresh token usage policy is "${policy || 'not set'}" (must be "OneTimeUse")`, + specSection: '4.3', + specUrl: specUrl('4.3'), + }; +} + +function checkDeprecatedGrants(ctx: AppCheckContext, strict: boolean): CheckResult[] { + const grants = ctx.app.oauthConfiguration?.enabledGrants || []; + const failures: CheckResult[] = []; + const severity: CheckSeverity = strict ? 'required' : 'warning'; + + if (grants.includes(GrantType.implicit)) { + failures.push({ + name: 'deprecatedGrants', + passed: false, + severity, + message: `Application "${ctx.appName}" (${ctx.appId}): Implicit grant is enabled (removed in OAuth 2.1)`, + specSection: '10.1', + specUrl: specUrl('10.1'), + }); + } + if (grants.includes(GrantType.password)) { + failures.push({ + name: 'deprecatedGrants', + passed: false, + severity, + message: `Application "${ctx.appName}" (${ctx.appId}): Password grant is enabled (removed in OAuth 2.1)`, + specSection: '10', + specUrl: specUrl('10'), + }); + } + return failures; +} + +/** + * DPoP is an instance-level capability, not a per-application setting. + * FusionAuth automatically handles DPoP when the client initiates a DPoP flow + * — there is no server-side toggle to enable it. The only prerequisite is an + * Enterprise license. + * + * See: https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/dpop + */ +function checkDpop(dpopFeatureActive: boolean): CheckResult | null { + if (!dpopFeatureActive) { + return { + name: 'dpop', + passed: false, + severity: 'warning', + message: 'DPoP unavailable: Enterprise license required. DPoP sender-constrains tokens to the client that requested them (§1.4.3).', + details: [ + 'DPoP requires no server-side configuration — FusionAuth handles it automatically when the client initiates a DPoP flow.', + 'However, an Enterprise license is required for this feature.', + 'See: https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/dpop', + ], + specSection: '1.4.3', + specUrl: specUrl('1.4.3'), + }; + } + return null; // pass — DPoP is available, clients can use it at will +} + +function checkTenantIssuer(tenant: Tenant): CheckResult | null { + const issuer = tenant.issuer || ''; + const tenantName = tenant.name || 'Unnamed Tenant'; + const tenantId = tenant.id || 'unknown'; + + if (issuer && issuer !== 'acme.com') { + return null; // pass + } + + const reason = issuer === 'acme.com' + ? 'still set to default "acme.com"' + : 'not configured'; + + return { + name: 'tenantIssuer', + passed: false, + severity: 'required', + message: `Tenant "${tenantName}" (${tenantId}): Issuer ${reason} (must be set to your domain)`, + }; +} + +function checkRefreshTokenRevocationOnReuse(tenant: Tenant): CheckResult | null { + const tenantName = tenant.name || 'Unnamed Tenant'; + const tenantId = tenant.id || 'unknown'; + + // onOneTimeTokenReuse is now properly typed in the v1.64.0 client. + const onReuse = tenant.jwtConfiguration?.refreshTokenRevocationPolicy?.onOneTimeTokenReuse === true; + + if (onReuse) { + return null; // pass + } + + return { + name: 'refreshTokenRevocationOnReuse', + passed: false, + severity: 'required', + message: `Tenant "${tenantName}" (${tenantId}): Refresh token revocation on one-time token reuse is not enabled`, + details: [ + 'Set tenant.jwtConfiguration.refreshTokenRevocationPolicy.onOneTimeTokenReuse = true', + 'This detects token theft when a one-time use refresh token is replayed.', + ], + specSection: '4.3', + specUrl: specUrl('4.3'), + }; +} + +function checkAuthCodeLifetime(tenant: Tenant): CheckResult | null { + const tenantName = tenant.name || 'Unnamed Tenant'; + const tenantId = tenant.id || 'unknown'; + const ttl = tenant.externalIdentifierConfiguration?.authorizationGrantIdTimeToLiveInSeconds; + + if (ttl === undefined || ttl === null) { + return null; // can't check, skip + } + + if (ttl <= 600) { + return null; // pass + } + + return { + name: 'authCodeLifetime', + passed: false, + severity: 'warning', + message: `Tenant "${tenantName}" (${tenantId}): Authorization code lifetime is ${ttl} seconds (recommend <= 600)`, + specSection: '7.5', + specUrl: specUrl('7.5'), + }; +} + +// -- Main Action ------------------------------------------------------------- + +const action = async function (options: { + key: string; + host: string; + applicationId?: string; + tenantId?: string; + strict: boolean; + json: boolean; + verbose: boolean; +}) { + logEvent('cli command check:oauth-2-1') + const {key: apiKey, host, applicationId, tenantId, strict, json: jsonOutput, verbose} = options; + + if (!jsonOutput) { + console.log(chalk.blue(`Checking OAuth 2.1 compliance on ${host}...`)); + console.log(chalk.blue(`Reference: draft-ietf-oauth-v2-1-15\n`)); + } + + const results: CheckResult[] = []; + + try { + const client = new FusionAuthClient(apiKey, host); + + // -- Fetch data ------------------------------------------------------ + + // Reactor status (for DPoP check — DPoP requires Enterprise license) + let dpopFeatureActive: boolean | undefined; + let dpopStatusError: unknown; + try { + const reactorResponse = await client.retrieveReactorStatus(); + if (reactorResponse.wasSuccessful()) { + dpopFeatureActive = reactorResponse.response.status?.dPoP === ReactorFeatureStatus.ACTIVE; + } else { + dpopFeatureActive = undefined; + } + } catch (e: unknown) { + dpopFeatureActive = undefined; + dpopStatusError = e; + } + + if (dpopFeatureActive === undefined && verbose && !jsonOutput) { + const errorDetail = dpopStatusError instanceof Error + ? `: ${dpopStatusError.message}` + : dpopStatusError + ? `: ${String(dpopStatusError)}` + : ''; + console.warn(chalk.yellow(`Warning: Unable to determine DPoP Reactor status${errorDetail}. DPoP availability is unknown.`)); + } + // Tenants + const tenantResponse = await client.retrieveTenants(); + if (!tenantResponse.wasSuccessful() || !tenantResponse.response.tenants) { + errorAndExit('Failed to retrieve tenants.'); + return; + } + + let tenants = tenantResponse.response.tenants; + if (tenantId) { + tenants = tenants.filter(t => t.id === tenantId); + if (tenants.length === 0) { + errorAndExit(`Tenant with ID "${tenantId}" not found.`); + return; + } + } + + // Applications + let allApps: Application[] = []; + if (applicationId) { + const appResponse = await client.retrieveApplication(applicationId); + if (!appResponse.wasSuccessful() || !appResponse.response.application) { + errorAndExit(`Application with ID "${applicationId}" not found.`); + return; + } + allApps = [appResponse.response.application]; + + // Validate the application belongs to the specified tenant + if (tenantId && allApps[0].tenantId !== tenantId) { + errorAndExit(`Application "${allApps[0].name || applicationId}" belongs to tenant "${allApps[0].tenantId}", not the specified tenant "${tenantId}".`); + return; + } + + // Narrow tenant-level checks to just this application's tenant + if (!tenantId) { + tenants = tenants.filter(t => t.id === allApps[0].tenantId); + } + } else { + const appsResponse = await client.retrieveApplications(); + if (!appsResponse.wasSuccessful() || !appsResponse.response.applications) { + errorAndExit('Failed to retrieve applications.'); + return; + } + allApps = appsResponse.response.applications; + } + + // Filter applications by tenant if needed + if (tenantId && !applicationId) { + allApps = allApps.filter(app => app.tenantId === tenantId); + } + + // Separate into checked and skipped in a single pass + const appsToCheck: Application[] = []; + const skippedApps: Application[] = []; + for (const app of allApps) { + if (shouldCheckApplication(app)) { + appsToCheck.push(app); + } else { + skippedApps.push(app); + } + } + + if (!jsonOutput) { + console.log(chalk.cyan(`Tenants checked: ${tenants.length}`)); + console.log(chalk.cyan(`Applications checked: ${appsToCheck.length}${tenantId ? ' (in selected tenant)' : applicationId ? '' : ' (across all tenants)'}`)); + console.log(chalk.cyan(`Applications skipped: ${skippedApps.length} (built-in FusionAuth apps or not using authorization_code + refresh_token grants)\n`)); + } + + if (appsToCheck.length === 0) { + if (applicationId) { + // The user explicitly requested this app but it was filtered out + const app = allApps[0]; + if (app && isBuiltInApplication(app)) { + if (!jsonOutput) { + console.log(chalk.yellow(`Application "${app.name || applicationId}" is a built-in FusionAuth application and is excluded from OAuth 2.1 checks.`)); + } + } else { + const grants = app?.oauthConfiguration?.enabledGrants || []; + if (!jsonOutput) { + console.log(chalk.yellow(`Application "${app?.name || applicationId}" does not use both authorization_code and refresh_token grants.`)); + console.log(chalk.yellow(`Enabled grants: ${grants.length > 0 ? grants.join(', ') : 'none'}`)); + } + } + } else { + if (!jsonOutput) { + console.log(chalk.yellow('No applications found using both authorization_code and refresh_token grants.')); + console.log(chalk.yellow('Nothing to check for OAuth 2.1 compliance.')); + } + } + } + + // -- Tenant-level checks --------------------------------------------- + + for (const tenant of tenants) { + const issuerResult = checkTenantIssuer(tenant); + if (issuerResult) results.push(issuerResult); + + const revocationResult = checkRefreshTokenRevocationOnReuse(tenant); + if (revocationResult) results.push(revocationResult); + + const authCodeResult = checkAuthCodeLifetime(tenant); + if (authCodeResult) results.push(authCodeResult); + } + + // -- Instance-level checks ------------------------------------------- + + const dpopResult = checkDpop(dpopFeatureActive ?? false); + if (dpopResult) results.push(dpopResult); + + // -- Application-level checks ---------------------------------------- + + for (const app of appsToCheck) { + const ctx: AppCheckContext = { + app, + appName: getAppName(app), + appId: getAppId(app), + }; + + if (verbose && !jsonOutput) { + console.log(chalk.cyan(`\nApplication: "${ctx.appName}" (${ctx.appId})`)); + } + + // Required checks + const pkceResult = checkPkce(ctx); + if (pkceResult) results.push(pkceResult); + if (verbose && !jsonOutput) { + console.log(pkceResult + ? chalk.red(` ✗ PKCE: ${ctx.app.oauthConfiguration?.proofKeyForCodeExchangePolicy || 'not set'}`) + : chalk.green(` ✓ PKCE: Required`)); + } + + const redirectResult = checkRedirectUriValidation(ctx); + if (redirectResult) results.push(redirectResult); + if (verbose && !jsonOutput) { + console.log(redirectResult + ? chalk.red(` ✗ Redirect URI validation: ${ctx.app.oauthConfiguration?.authorizedURLValidationPolicy || 'not set'}`) + : chalk.green(` ✓ Redirect URI validation: ExactMatch`)); + } + + const httpsResults = checkHttpsEnforcement(ctx); + results.push(...httpsResults); + if (verbose && !jsonOutput) { + if (httpsResults.length > 0) { + for (const r of httpsResults) { + console.log(chalk.red(` ✗ ${r.message}`)); + } + } else { + console.log(chalk.green(` ✓ HTTPS enforcement: All redirect URIs valid`)); + } + } + + const rotationResult = checkRefreshTokenRotation(ctx); + if (rotationResult) results.push(rotationResult); + if (verbose && !jsonOutput) { + console.log(rotationResult + ? chalk.red(` ✗ Refresh token rotation: ${ctx.app.jwtConfiguration?.refreshTokenUsagePolicy || 'not set'}`) + : chalk.green(` ✓ Refresh token rotation: OneTimeUse`)); + } + + // Warning checks + const deprecatedResults = checkDeprecatedGrants(ctx, strict); + results.push(...deprecatedResults); + if (verbose && !jsonOutput) { + if (deprecatedResults.length > 0) { + for (const r of deprecatedResults) { + const icon = strict ? '✗' : '⚠'; + const color = strict ? chalk.red : chalk.yellow; + console.log(color(` ${icon} ${r.message}`)); + } + } else { + console.log(chalk.green(` ✓ No deprecated grants enabled`)); + } + } + } + + // -- Aggregate results ----------------------------------------------- + + const criticalFailures = results.filter(r => r.severity === 'required' && !r.passed); + const warnings = results.filter(r => r.severity === 'warning' && !r.passed); + const allRequiredPassed = criticalFailures.length === 0; + + // -- Summary by check name ------------------------------------------- + + const pkceTotal = appsToCheck.length; + const pkcePass = pkceTotal - results.filter(r => r.name === 'pkce').length; + + const redirectTotal = appsToCheck.length; + const redirectPass = redirectTotal - results.filter(r => r.name === 'redirectUriValidation').length; + + const httpsFailCount = results.filter(r => r.name === 'httpsEnforcement').length; + + const rotationTotal = appsToCheck.length; + const rotationPass = rotationTotal - results.filter(r => r.name === 'refreshTokenRotation').length; + + const revocationFailCount = results.filter(r => r.name === 'refreshTokenRevocationOnReuse').length; + + const issuerFailCount = results.filter(r => r.name === 'tenantIssuer').length; + + const dpopAvailable = dpopResult === null; + + const authCodeFailCount = results.filter(r => r.name === 'authCodeLifetime').length; + + const deprecatedFailCount = results.filter(r => r.name === 'deprecatedGrants').length; + + // -- Output ---------------------------------------------------------- + + if (jsonOutput) { + const output: JsonOutput = { + compliant: allRequiredPassed, + tenantsChecked: tenants.length, + applicationsChecked: appsToCheck.length, + applicationsSkipped: skippedApps.length, + filters: { + tenantId: tenantId || null, + applicationId: applicationId || null, + }, + checks: {}, + criticalIssues: criticalFailures.map(r => r.message), + warnings: warnings.map(r => r.message), + educationalLinks: { + 'oauth21Spec': SPEC_BASE, + 'pkce': specUrl('7.5'), + 'redirectUri': specUrl('4.1.3'), + 'https': specUrl('1.5'), + 'senderConstrainedTokens': specUrl('1.4.3'), + 'refreshTokenSecurity': specUrl('4.3'), + 'deprecatedGrants': specUrl('10'), + 'fusionAuthOAuthConfig': 'https://fusionauth.io/docs/apis/applications', + 'fusionAuthTenantConfig': 'https://fusionauth.io/docs/apis/tenants', + 'fusionAuthDPoP': 'https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/dpop', + }, + }; + + // Add individual check results + output.checks['pkce'] = { + severity: 'required', + passed: pkcePass === pkceTotal, + message: pkcePass === pkceTotal + ? `All applications require PKCE (${pkcePass}/${pkceTotal})` + : `${pkceTotal - pkcePass} application(s) do not require PKCE (${pkcePass}/${pkceTotal} compliant)`, + specSection: '7.5', + specUrl: specUrl('7.5'), + }; + output.checks['redirectUriValidation'] = { + severity: 'required', + passed: redirectPass === redirectTotal, + message: redirectPass === redirectTotal + ? `All applications use exact match redirect URI validation (${redirectPass}/${redirectTotal})` + : `${redirectTotal - redirectPass} application(s) allow wildcard redirect URIs (${redirectPass}/${redirectTotal} compliant)`, + specSection: '4.1.3', + specUrl: specUrl('4.1.3'), + }; + output.checks['httpsEnforcement'] = { + severity: 'required', + passed: httpsFailCount === 0, + message: httpsFailCount === 0 + ? 'All redirect URIs use HTTPS (or localhost)' + : `${httpsFailCount} non-HTTPS redirect URI(s) found`, + details: results.filter(r => r.name === 'httpsEnforcement').map(r => r.message), + specSection: '1.5', + specUrl: specUrl('1.5'), + }; + output.checks['refreshTokenRotation'] = { + severity: 'required', + passed: rotationPass === rotationTotal, + message: rotationPass === rotationTotal + ? `All applications use one-time use refresh tokens (${rotationPass}/${rotationTotal})` + : `${rotationTotal - rotationPass} application(s) do not use one-time use refresh tokens (${rotationPass}/${rotationTotal} compliant)`, + specSection: '4.3', + specUrl: specUrl('4.3'), + }; + output.checks['refreshTokenRevocationOnReuse'] = { + severity: 'required', + passed: revocationFailCount === 0, + message: revocationFailCount === 0 + ? 'All tenants have refresh token revocation on reuse enabled' + : `${revocationFailCount} tenant(s) do not have refresh token revocation on reuse enabled`, + specSection: '4.3', + specUrl: specUrl('4.3'), + }; + output.checks['tenantIssuer'] = { + severity: 'required', + passed: issuerFailCount === 0, + message: issuerFailCount === 0 + ? `All tenant issuers properly configured (${tenants.length}/${tenants.length})` + : `${issuerFailCount} tenant(s) have improperly configured issuers`, + }; + output.checks['dpop'] = { + severity: 'warning', + passed: dpopAvailable, + message: dpopAvailable + ? 'DPoP available (Enterprise license active). Clients can initiate DPoP flows — no server-side configuration needed.' + : 'DPoP unavailable (Enterprise license required). Sender-constrained tokens are recommended by OAuth 2.1 §1.4.3.', + specSection: '1.4.3', + specUrl: specUrl('1.4.3'), + }; + output.checks['authCodeLifetime'] = { + severity: 'warning', + passed: authCodeFailCount === 0, + message: authCodeFailCount === 0 + ? 'Authorization code lifetime within recommended range' + : `${authCodeFailCount} tenant(s) have authorization code lifetime exceeding 600 seconds`, + specSection: '7.5', + specUrl: specUrl('7.5'), + }; + output.checks['deprecatedGrants'] = { + severity: strict ? 'required' : 'warning', + passed: deprecatedFailCount === 0, + message: deprecatedFailCount === 0 + ? 'No deprecated grants enabled' + : `${deprecatedFailCount} deprecated grant(s) found`, + details: results.filter(r => r.name === 'deprecatedGrants').map(r => r.message), + specSection: '10', + specUrl: specUrl('10'), + }; + + console.log(JSON.stringify(output, null, 2)); + } else { + // Human-readable output + if (!verbose) { + // Summary lines + console.log(pkcePass === pkceTotal + ? chalk.green(`✓ PKCE enforcement: Required (${pkcePass}/${pkceTotal} applications)`) + : chalk.red(`✗ PKCE enforcement: ${pkceTotal - pkcePass}/${pkceTotal} applications not compliant`)); + + console.log(redirectPass === redirectTotal + ? chalk.green(`✓ Redirect URI validation: ExactMatch (${redirectPass}/${redirectTotal} applications)`) + : chalk.red(`✗ Redirect URI validation: ${redirectTotal - redirectPass}/${redirectTotal} applications using wildcards`)); + + console.log(httpsFailCount === 0 + ? chalk.green(`✓ HTTPS enforcement: All redirect URIs valid`) + : chalk.red(`✗ HTTPS enforcement: ${httpsFailCount} non-HTTPS redirect URI(s) found`)); + + console.log(rotationPass === rotationTotal + ? chalk.green(`✓ Refresh token rotation: OneTimeUse (${rotationPass}/${rotationTotal} applications)`) + : chalk.red(`✗ Refresh token rotation: ${rotationTotal - rotationPass}/${rotationTotal} applications not using OneTimeUse`)); + + console.log(revocationFailCount === 0 + ? chalk.green(`✓ Refresh token revocation on reuse: Enabled (${tenants.length}/${tenants.length} tenants)`) + : chalk.red(`✗ Refresh token revocation on reuse: Disabled on ${revocationFailCount} tenant(s)`)); + + console.log(issuerFailCount === 0 + ? chalk.green(`✓ Tenant issuer: Properly configured (${tenants.length}/${tenants.length} tenants)`) + : chalk.red(`✗ Tenant issuer: ${issuerFailCount} tenant(s) not properly configured`)); + + console.log(dpopAvailable + ? chalk.green(`✓ DPoP (sender-constrained tokens): Available (Enterprise license active)`) + : chalk.yellow(`⚠ DPoP (sender-constrained tokens): Unavailable (Enterprise license required)`)); + + console.log(authCodeFailCount === 0 + ? chalk.green(`✓ Authorization code lifetime: Within recommended range`) + : chalk.yellow(`⚠ Authorization code lifetime: ${authCodeFailCount} tenant(s) exceed 600 seconds`)); + + const deprecatedIcon = strict ? '✗' : '⚠'; + const deprecatedColor = strict ? chalk.red : chalk.yellow; + console.log(deprecatedFailCount === 0 + ? chalk.green(`✓ Deprecated grants: None enabled`) + : deprecatedColor(`${deprecatedIcon} Deprecated grants: ${deprecatedFailCount} deprecated grant(s) found${strict ? '' : ' (use --strict to fail)'}`)); + } + + // Final summary + console.log(chalk.blue('\n=== OAuth 2.1 Compliance Summary ===\n')); + + if (allRequiredPassed) { + console.log(chalk.green.bold('SUCCESS: Your FusionAuth instance meets OAuth 2.1 requirements.')); + if (warnings.length > 0) { + console.log(chalk.yellow(`\nWarnings (RECOMMENDED):`)); + for (const w of warnings) { + console.log(chalk.yellow(` - ${w.message}`)); + } + } + } else { + console.log(chalk.red.bold('FAILED: Your FusionAuth instance is NOT OAuth 2.1 compliant.\n')); + + console.log(chalk.red('Critical issues (MUST FIX):')); + for (const f of criticalFailures) { + console.log(chalk.red(` - ${f.message}`)); + if (f.details) { + for (const d of f.details) { + console.log(chalk.red(` ${d}`)); + } + } + } + + if (warnings.length > 0) { + console.log(chalk.yellow('\nWarnings (RECOMMENDED):')); + for (const w of warnings) { + console.log(chalk.yellow(` - ${w.message}`)); + } + } + } + + // Educational links + console.log(chalk.blue('\nFor more information:')); + console.log(chalk.cyan(` - OAuth 2.1 Specification: ${SPEC_BASE}`)); + console.log(chalk.cyan(` - PKCE (Section 7.5): ${specUrl('7.5')}`)); + console.log(chalk.cyan(` - Redirect URI (Section 4.1.3): ${specUrl('4.1.3')}`)); + console.log(chalk.cyan(` - HTTPS (Section 1.5): ${specUrl('1.5')}`)); + console.log(chalk.cyan(` - Sender-Constrained Tokens (Section 1.4.3): ${specUrl('1.4.3')}`)); + console.log(chalk.cyan(` - Refresh Token Security (Section 4.3): ${specUrl('4.3')}`)); + console.log(chalk.cyan(` - Deprecated Grants (Section 10): ${specUrl('10')}`)); + console.log(chalk.cyan(` - FusionAuth OAuth Configuration: https://fusionauth.io/docs/apis/applications`)); + console.log(chalk.cyan(` - FusionAuth Tenant Configuration: https://fusionauth.io/docs/apis/tenants`)); + console.log(chalk.cyan(` - FusionAuth DPoP: https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/dpop`)); + } + + if (!allRequiredPassed) { + process.exit(1); + } + + } catch (e: unknown) { + errorAndExit('OAuth 2.1 compliance check error:', e); + } +} + +// -- Command ----------------------------------------------------------------- + +// noinspection JSUnusedGlobalSymbols +export const checkOAuth21 = new Command('check:oauth-2-1') + .description('Checks FusionAuth configuration for OAuth 2.1 compliance (draft-ietf-oauth-v2-1-15)') + .addOption(apiKeyOption) + .addOption(hostOption) + .addOption(applicationIdOption) + .addOption(tenantIdOption) + .addOption(strictOption) + .addOption(jsonOption) + .addOption(verboseOption) + .action(action); diff --git a/src/commands/email-upload.ts b/src/commands/email-upload.ts index c745107..9aefd48 100644 --- a/src/commands/email-upload.ts +++ b/src/commands/email-upload.ts @@ -94,7 +94,7 @@ export const emailUpload = new Command('email:upload') } try { - const request: EmailTemplateRequest = {emailTemplate: removeUndefinedObjects.default(emailTemplate)}; + const request: EmailTemplateRequest = {emailTemplate: removeUndefinedObjects(emailTemplate)}; if (!templateExists) { await client.createEmailTemplate(templateId, request); } else if (overwrite) { diff --git a/src/commands/import-generate.ts b/src/commands/import-generate.ts index ab79e76..9ebecb7 100644 --- a/src/commands/import-generate.ts +++ b/src/commands/import-generate.ts @@ -71,7 +71,7 @@ function generateData(numObjects: number, appId: string, groupId: string, startN birthDate: faker.date.past().toISOString().split('T')[0], data: { displayName: faker.person.firstName() + ' ' + faker.person.lastName(), - favoriteColors: [faker.internet.color(), faker.internet.color()] + favoriteColors: [faker.color.rgb(), faker.color.rgb()] }, email: `example${i + 1 + startNumber}@example.com`, encryptionScheme: 'salted-pbkdf2-hmac-sha256', @@ -103,7 +103,7 @@ function generateData(numObjects: number, appId: string, groupId: string, startN }, insertInstant: faker.date.past().getTime(), preferredLanguages: ['en_US'], - username: faker.internet.userName(), + username: faker.internet.username(), verified: faker.datatype.boolean() } ], diff --git a/src/commands/index.ts b/src/commands/index.ts index 07f0f21..33dd81d 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,4 +1,5 @@ export * from './check-common-config.js'; +export * from './check-oauth-2-1.js'; export * from './email-create.js'; export * from './email-download.js'; export * from './email-duplicate.js'; diff --git a/src/commands/message-upload.ts b/src/commands/message-upload.ts index 5654934..dbc4cdb 100644 --- a/src/commands/message-upload.ts +++ b/src/commands/message-upload.ts @@ -94,7 +94,7 @@ export const messageUpload = new Command('message:upload') } try { - const request: MessageTemplateRequest = {messageTemplate: removeUndefinedObjects.default(messageTemplate)}; + const request: MessageTemplateRequest = {messageTemplate: removeUndefinedObjects(messageTemplate)}; if (!templateExists) { await client.createMessageTemplate(templateId, request); } else if (overwrite) { diff --git a/src/utilities/apply/types.ts b/src/utilities/apply/types.ts index d1d29e2..640cc7e 100644 --- a/src/utilities/apply/types.ts +++ b/src/utilities/apply/types.ts @@ -6,38 +6,41 @@ /** * HTTP methods supported by the apply system */ -export enum HTTPMethod { - PATCH = 'PATCH', - POST = 'POST', - PUT = 'PUT', -} +export const HTTPMethod = { + PATCH: 'PATCH', + POST: 'POST', + PUT: 'PUT', +} as const; +export type HTTPMethod = typeof HTTPMethod[keyof typeof HTTPMethod]; /** * Status of a apply step execution */ -export enum StepStatus { - FAILED = 'failed', - PENDING = 'pending', - SKIPPED = 'skipped', - SUCCESS = 'success', - WARNING = 'warning', -} +export const StepStatus = { + FAILED: 'failed', + PENDING: 'pending', + SKIPPED: 'skipped', + SUCCESS: 'success', + WARNING: 'warning', +} as const; +export type StepStatus = typeof StepStatus[keyof typeof StepStatus]; /** * Categories of errors that can occur during apply execution */ -export enum ErrorCategory { - SCHEMA_INVALID = 'schema_invalid', - VARIABLE_NOT_DEFINED = 'variable_not_defined', - AUTHENTICATION_FAILED = 'authentication_failed', - NETWORK_ERROR = 'network_error', - RESOURCE_CONFLICT = 'resource_conflict', - SERVER_ERROR = 'server_error', - INVALID_PAYLOAD = 'invalid_payload', - FILE_NOT_FOUND = 'file_not_found', - UNKNOWN = 'unknown', -} +export const ErrorCategory = { + SCHEMA_INVALID: 'schema_invalid', + VARIABLE_NOT_DEFINED: 'variable_not_defined', + AUTHENTICATION_FAILED: 'authentication_failed', + NETWORK_ERROR: 'network_error', + RESOURCE_CONFLICT: 'resource_conflict', + SERVER_ERROR: 'server_error', + INVALID_PAYLOAD: 'invalid_payload', + FILE_NOT_FOUND: 'file_not_found', + UNKNOWN: 'unknown', +} as const; +export type ErrorCategory = typeof ErrorCategory[keyof typeof ErrorCategory]; /** * Variable definitions that can be referenced in kickstart requests diff --git a/src/utils.ts b/src/utils.ts index ec2da2b..53f659d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,3 @@ -import ClientResponse from '@fusionauth/typescript-client/build/src/ClientResponse.js'; import {Errors} from '@fusionauth/typescript-client'; import fs, { readFileSync } from 'node:fs' import { dirname } from 'node:path'; @@ -8,28 +7,34 @@ import { randomUUID } from 'node:crypto'; import chalk from 'chalk'; import boxen from 'boxen'; import { execSync } from 'node:child_process'; - import { PostHog } from 'posthog-node' import * as dotenv from 'dotenv' dotenv.config() +/** Shape of a FusionAuth ClientResponse — used for duck-type checking without importing internals. */ +interface ClientResponseLike { + wasSuccessful: () => boolean; + response: unknown; + exception?: Error; +} + export const posthogClient = new PostHog( 'phc_nB6C2uZX2LA6ce6VAaWZxBYPtq1wYH5x8A3n36DaLzQ', { host: 'https://us.i.posthog.com' } ) - - export const __dirname = dirname(fileURLToPath(import.meta.url)); /** * Checks if the response is a client response * @param response */ -export const isClientResponse = (response: any): response is ClientResponse.default => { - return response.wasSuccessful !== undefined; +export const isClientResponse = (response: any): response is ClientResponseLike => { + return response !== null + && typeof response === 'object' + && typeof response.wasSuccessful === 'function'; } /**