diff --git a/.eslintrc b/.eslintrc
index fc09a8f..adb1e42 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -62,8 +62,7 @@
{
"devDependencies": true,
"optionalDependencies": false,
- "peerDependencies": false,
- "packageDir": "./"
+ "peerDependencies": false
}
],
"@typescript-eslint/consistent-type-imports": [
@@ -72,6 +71,13 @@
"prefer": "type-imports",
"disallowTypeAnnotations": false
}
+ ],
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ "argsIgnorePattern": "^_",
+ "varsIgnorePattern": "^_"
+ }
]
},
"env": {
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1e8be7a..4a02ba4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,10 +1,12 @@
name: Continuous Integration
-on: [pull_request]
+on: pull_request
permissions:
id-token: write
contents: read
+ actions: read
checks: write
+ pull-requests: write
jobs:
build:
@@ -12,30 +14,31 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [18.x, 20.x, 22.x]
+ node-version: [20.x, 22.x, 24.x]
steps:
- name: Checkout
uses: actions/checkout@v4
-
- name: Use Node ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
+
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- - uses: actions/cache@v2
+
+ - uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
- - name: PNPM
+ - name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
- run: pnpm run build
+ run: pnpm build
lint:
name: Lint
@@ -43,35 +46,34 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
+
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22.x'
+
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
-
- - uses: actions/cache@v2
+
+ - uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
- - name: PNPM
+ - name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
- run: pnpm run lint
-
- - name: Validate Packages
- run: pnpm manypkg check
+ run: pnpm lint
test:
- name: Test
+ name: Unit Tests
runs-on: ubuntu-latest
strategy:
matrix:
- project: ['doubles.jest', 'doubles.sinon', 'core.unit', 'doubles.vitest', 'di.nestjs', 'di.inversify', 'unit']
+ project: ['cli', 'governance', 'changesets', 'json-schema-differ', 'types']
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -80,47 +82,61 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '22.x'
+
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- - uses: actions/cache@v2
+ - uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
- - name: PNPM
+ - name: Install dependencies
run: pnpm install --frozen-lockfile
+ - name: Build
+ run: pnpm build
+
- name: Create Coverage Directory
run: mkdir -p ${{ github.workspace }}/coverage
- name: Test
- run: pnpm --filter @contractual/${{ matrix.project }} run test
+ run: pnpm lerna run test --scope @contractual/${{ matrix.project }} --stream
+ continue-on-error: true
env:
- JEST_JUNIT_OUTPUT_NAME: ${{ matrix.project }}.xml
- JEST_JUNIT_OUTPUT_DIR: ${{ github.workspace }}/test-reports
- JUNIT_OUTPUT_NAME: ${{ matrix.project }}
- JUNIT_OUTPUT_DIR: ${{ github.workspace }}/test-reports
COVERAGE_DIR: ${{ github.workspace }}/coverage
COVERAGE_FILE: coverage-${{ matrix.project }}.xml
- - name: Tests Results
- uses: dorny/test-reporter@v1
- if: always()
+ e2e:
+ name: E2E Tests
+ runs-on: ubuntu-latest
+ needs: [build]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
with:
- reporter: 'jest-junit'
- name: Tests Results (${{ matrix.project }})
- path: ${{ github.workspace }}/test-reports/${{ matrix.project }}.xml
- fail-on-error: false
-
-# - name: Upload Report to Codecov
-# uses: codecov/codecov-action@v3
-# with:
-# name: codecov-umbrella
-# flags: ${{ matrix.project }}
-# token: ${{ secrets.CODECOV_TOKEN }}
-# fail_ci_if_error: true
-# files: ${{ github.workspace }}/coverage/coverage-${{ matrix.project }}.xml
-# verbose: true
+ node-version: '22.x'
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - uses: actions/cache@v4
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build
+ run: pnpm build
+
+ - name: Run E2E Tests
+ run: pnpm test:e2e
diff --git a/.github/workflows/e2e-release.yml b/.github/workflows/e2e-release.yml
new file mode 100644
index 0000000..9ab5fd0
--- /dev/null
+++ b/.github/workflows/e2e-release.yml
@@ -0,0 +1,158 @@
+name: E2E Release Simulation
+env:
+ CI: true
+
+on:
+ workflow_call:
+ inputs:
+ target_branch:
+ description: 'Branch to test release from'
+ required: true
+ type: string
+ workflow_dispatch:
+ inputs:
+ target_branch:
+ description: 'Branch to test release from'
+ required: true
+ type: string
+ default: 'next'
+
+permissions:
+ contents: write
+ id-token: write
+
+jobs:
+ e2e:
+ name: E2E (${{ matrix.e2e-project }}, Node ${{ matrix.node-version }})
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ e2e-project: ['cli-basic', 'cli-lifecycle', 'packages-import']
+ node-version: [20.x, 22.x, 24.x]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.target_branch }}
+ fetch-depth: 0
+
+ - name: Setup Node ${{ matrix.node-version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Start Verdaccio
+ run: docker compose -f local-e2e.docker-compose.yaml up -d verdaccio
+
+ - name: Wait for Verdaccio
+ run: |
+ for i in {1..30}; do
+ if curl -s http://localhost:4873 > /dev/null; then
+ echo "Verdaccio is ready"
+ break
+ fi
+ echo "Waiting for Verdaccio..."
+ sleep 1
+ done
+
+ - name: Build
+ run: pnpm build
+
+ - name: Setup Registry
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ registry-url: http://localhost:4873
+ scope: '@contractual'
+ always-auth: false
+
+ - name: Install jq
+ run: sudo apt-get install -y jq
+
+ - name: Config Git
+ run: |
+ git config --global user.email "e2e@contractual.dev"
+ git config --global user.name "Contractual e2e"
+
+ - name: Remove provenance from package.json files
+ run: |
+ find packages -name 'package.json' | while read filename; do
+ jq 'del(.publishConfig.provenance)' "$filename" > temp.json && mv temp.json "$filename"
+ done
+
+ - name: Commit Provenance Removal
+ run: |
+ git add .
+ git commit -am "chore: remove provenance for e2e"
+
+ - name: Version Packages
+ run: |
+ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
+ npx lerna version --yes \
+ --conventional-commits \
+ --conventional-prerelease \
+ --preid e2e \
+ --no-changelog \
+ --allow-branch "$BRANCH_NAME" \
+ --no-git-tag-version \
+ --no-push \
+ --force-publish \
+ --no-commit-hooks
+
+ - name: Commit Packages Versions
+ run: |
+ git add .
+ git commit -am "bump versions"
+
+ - name: Capture Versions for Report
+ run: |
+ echo "## E2E Test Results" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Project:** \`${{ matrix.e2e-project }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Node:** \`${{ matrix.node-version }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Versions:" >> $GITHUB_STEP_SUMMARY
+ lerna ls --json | jq -r '.[] | "- **\(.name)** -> `v\(.version)`"' >> $GITHUB_STEP_SUMMARY
+
+ - name: Publish Packages to Verdaccio
+ run: |
+ npx lerna publish from-package --yes \
+ --no-git-tag-version \
+ --no-push \
+ --no-git-reset \
+ --exact \
+ --dist-tag e2e
+
+ - name: Clean Source (simulate fresh install)
+ run: |
+ rm -rf packages
+ rm -rf node_modules
+ rm pnpm-lock.yaml
+ rm package.json
+ rm -f .npmrc
+
+ - name: Install E2E Dependencies from Verdaccio
+ run: |
+ cd "${{ github.workspace }}/e2e/${{ matrix.e2e-project }}"
+ npm install --registry http://localhost:4873 --no-package-lock
+
+ - name: Execute Tests
+ run: |
+ cd "${{ github.workspace }}/e2e/${{ matrix.e2e-project }}"
+ npm test
+
+ - name: Test Success Summary
+ if: success()
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Test Passed" >> $GITHUB_STEP_SUMMARY
+ echo "Packages work correctly when published" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml
index f104219..7bb567e 100644
--- a/.github/workflows/publish-packages.yml
+++ b/.github/workflows/publish-packages.yml
@@ -20,145 +20,87 @@ on:
- 'alpha'
- 'beta'
required: true
- default: 'dev'
- strategy:
- description: 'Release Strategy'
+ default: 'next'
+ target_branch:
+ description: 'Target branch to release from'
type: choice
options:
- - 'from-git'
- - 'from-package'
+ - 'next'
+ - 'master'
required: true
- default: 'from-package'
+ default: 'next'
jobs:
- e2e:
- name: Build and Test
+ publish:
+ name: Publish to NPM
runs-on: ubuntu-latest
- strategy:
- matrix:
- e2e-project: ['jest/nestjs', 'sinon/nestjs', 'vitest/nestjs', 'jest/inversify', 'sinon/inversify', 'vitest/inversify']
- node-version: [16.x, 18.x, 20.x]
- exclude:
- - e2e-project: 'vitest/inversify'
- node-version: '16.x'
- - e2e-project: 'vitest/nestjs'
- node-version: '16.x'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.target_branch }}
+ fetch-depth: 0
- - name: Remove Vitest If Needed
- if: ${{ matrix.node-version == '16.x' }}
- run: |
- rm -rf packages/doubles/vitest
- git config --global user.email "ci@suites.dev"
- git config --global user.name "Suites CI"
- git add .
- git commit -am "remove vitest temp"
-
- - name: Setup Node ${{ matrix.node-version }}
+ - name: Setup Node
uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version: '22.x'
+ registry-url: https://registry.npmjs.org/
+ scope: '@contractual'
+ always-auth: true
+
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
-
- - name: PNPM
- run: pnpm install --frozen-lockfile
- - name: Run Verdaccio Docker
- run: |
- docker run -d --name verdaccio \
- -p 4873:4873 \
- -v ${{ github.workspace }}/e2e/config.yaml:/verdaccio/conf/config.yaml \
- verdaccio/verdaccio
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
- name: Build
- run: pnpm build
+ run: pnpm lerna run build
- - name: Setup Registry
- uses: actions/setup-node@v4
- with:
- node-version: ${{ matrix.node-version }}
- registry-url: http://localhost:4873
- scope: '@suites'
- always-auth: false
-
- - name: Install jq
- run: sudo apt-get install jq
-
- - name: Remove provenance from publishConfig
- run: |
- find packages -name 'package.json' | while read filename; do
- jq 'del(.publishConfig.provenance)' "$filename" > temp.json && mv temp.json "$filename"
- done
-
- - name: Commit Change
+ - name: Capture Versions for Report
run: |
- git config --global user.email "e2e@suites.dev"
- git config --global user.name "Suites e2e"
- git add .
- git commit -am "remove provenance"
+ echo "## Publishing to NPM" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Registry:** \`https://registry.npmjs.org/\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Dist Tag:** \`${{ github.event.inputs.dist_tag }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Branch:** \`${{ github.event.inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Packages:" >> $GITHUB_STEP_SUMMARY
+ lerna ls --json | jq -r '.[] | "- **\(.name)** -> `v\(.version)`"' >> $GITHUB_STEP_SUMMARY
- name: Publish Packages
run: |
- pnpm publish -r \
- --no-git-checks \
- --access public \
- --tag ci \
- --force
- - name: Setup and Test
- run: |
- IFS='/' read -r library framework <<< "${{ matrix.e2e-project }}"
- echo "FRAMEWORK=$framework" >> $GITHUB_ENV
- echo "LIBRARY=$library" >> $GITHUB_ENV
-
- - name: Clean Source
- run: |
- rm -rf packages
- rm -rf node_modules
+ npx lerna publish from-package --yes \
+ --dist-tag ${{ github.event.inputs.dist_tag }} \
+ --no-git-reset
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- - name: Install Dependencies
+ - name: Generate Success Summary
+ if: success()
run: |
- cd "$PWD/e2e/$LIBRARY/$FRAMEWORK"
- npm install --no-cache --no-package-lock
- npm install --dev --no-package-lock @types/node@${{ matrix.node-version }}
-
- - name: Execute Test
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Publish Successful" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "All packages have been successfully published to npm!" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Installation command:**" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
+ echo "npm install @contractual/cli@${{ github.event.inputs.dist_tag }}" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+
+ - name: Generate Failure Summary
+ if: failure()
run: |
- cd "$PWD/e2e/$LIBRARY/$FRAMEWORK"
- npm test
-
- publish:
- name: Publish Packages
- needs: [e2e]
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Registry
- uses: actions/setup-node@v4
- with:
- registry-url: https://registry.npmjs.org/
- scope: '@suites'
- always-auth: true
- - name: Install pnpm
- uses: pnpm/action-setup@v4
- with:
- version: 9.15.4
-
- - name: pnpm
- run: pnpm install --frozen-lockfile
-
- - name: Build
- run: pnpm build
-
- - name: Publish Packages
- run: pnpm publish -r ${{ github.event.inputs.strategy }} --access public --tag ${{ github.event.inputs.dist_tag }}
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Publish Failed" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "The publish step failed. Check the logs above for details." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Common issues:**" >> $GITHUB_STEP_SUMMARY
+ echo "- Version already exists in npm registry" >> $GITHUB_STEP_SUMMARY
+ echo "- Authentication token is invalid or expired" >> $GITHUB_STEP_SUMMARY
+ echo "- Network connectivity issues" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml
index c6c8cba..43032a0 100644
--- a/.github/workflows/release-packages.yml
+++ b/.github/workflows/release-packages.yml
@@ -50,6 +50,22 @@ jobs:
ref: ${{ github.event.inputs.target_branch }}
fetch-depth: 0
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22.x'
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build
+ run: pnpm build
+
- name: Config Git User
run: |
git config --global user.name "${{ github.actor }}"
@@ -58,27 +74,24 @@ jobs:
- name: Prerelease Version (Exact Version)
if: ${{ github.event.inputs.release_type == 'prerelease' && github.event.inputs.exact_version }}
run: |
- pnpm version ${{ github.event.inputs.exact_version }} \
- --workspaces-update \
- --no-git-tag-version \
- --no-commit-hooks
+ npx lerna version ${{ github.event.inputs.exact_version }} --yes --no-changelog
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Prerelease Version
if: ${{ github.event.inputs.release_type == 'prerelease' && !github.event.inputs.exact_version }}
run: |
- pnpm version prerelease \
+ npx lerna version --yes \
+ --conventional-commits \
+ --conventional-prerelease \
--preid ${{ github.event.inputs.preid }} \
- --workspaces-update \
- --no-git-tag-version \
- --no-commit-hooks
+ --no-changelog
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Graduate Version
if: ${{ github.event.inputs.release_type == 'graduate' }}
- run: pnpm version --workspaces-update from-git
+ run: npx lerna version --conventional-graduate --yes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -88,3 +101,19 @@ jobs:
git push origin --tags
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Generate Release Summary
+ run: |
+ echo "## Release Prepared" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Branch:** \`${{ github.event.inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Release Type:** \`${{ github.event.inputs.release_type }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Preid:** \`${{ github.event.inputs.preid }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Tagged Packages" >> $GITHUB_STEP_SUMMARY
+ git tag --sort=-creatordate | head -10 | while read tag; do
+ echo "- \`$tag\`" >> $GITHUB_STEP_SUMMARY
+ done
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
+ echo "Run the **Publish Packages** workflow to publish to npm" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/release-preview.yml b/.github/workflows/release-preview.yml
new file mode 100644
index 0000000..46b46ae
--- /dev/null
+++ b/.github/workflows/release-preview.yml
@@ -0,0 +1,171 @@
+name: Release Preview
+
+on:
+ workflow_dispatch:
+ inputs:
+ target_branch:
+ description: 'Branch to preview release from'
+ type: choice
+ options:
+ - 'next'
+ - 'master'
+ required: true
+ default: 'next'
+ release_type:
+ description: 'Release Type'
+ type: choice
+ options:
+ - 'prerelease'
+ - 'graduate'
+ - 'auto'
+ required: true
+ default: 'auto'
+ preid:
+ description: 'Prerelease ID (for prerelease type)'
+ type: choice
+ options:
+ - 'next'
+ - 'rc'
+ - 'alpha'
+ - 'beta'
+ - 'dev'
+ required: false
+ default: 'next'
+
+permissions:
+ contents: read
+
+jobs:
+ preview:
+ name: Preview Release
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.target_branch }}
+ fetch-depth: 0
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22.x'
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Install conventional-changelog-cli
+ run: npm install -g conventional-changelog-cli
+
+ - name: Config Git
+ run: |
+ git config --global user.email "preview@contractual.dev"
+ git config --global user.name "Release Preview Bot"
+
+ - name: Show Changed Packages
+ run: |
+ echo "## Changed Packages" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Packages that have changed since last release:" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ npx lerna changed --json 2>/dev/null | jq -r '.[] | "- **\(.name)** (current: `v\(.version)`)"' >> $GITHUB_STEP_SUMMARY || echo "No changed packages" >> $GITHUB_STEP_SUMMARY
+
+ - name: Preview Versions (Prerelease)
+ if: ${{ inputs.release_type == 'prerelease' }}
+ run: |
+ npx lerna version prerelease --yes \
+ --preid ${{ inputs.preid }} \
+ --no-git-tag-version \
+ --no-push \
+ --allow-branch ${{ inputs.target_branch }}
+
+ - name: Preview Versions (Graduate)
+ if: ${{ inputs.release_type == 'graduate' }}
+ run: |
+ npx lerna version --yes \
+ --conventional-graduate \
+ --no-git-tag-version \
+ --no-push \
+ --allow-branch ${{ inputs.target_branch }}
+
+ - name: Preview Versions (Auto - Conventional Commits)
+ if: ${{ inputs.release_type == 'auto' }}
+ run: |
+ npx lerna version --yes \
+ --conventional-commits \
+ --no-git-tag-version \
+ --no-push \
+ --allow-branch ${{ inputs.target_branch }}
+
+ - name: Generate Version Summary
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Proposed Versions" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Release Type:** \`${{ inputs.release_type }}\`" >> $GITHUB_STEP_SUMMARY
+ if [ "${{ inputs.release_type }}" = "prerelease" ]; then
+ echo "**Prerelease ID:** \`${{ inputs.preid }}\`" >> $GITHUB_STEP_SUMMARY
+ fi
+ echo "" >> $GITHUB_STEP_SUMMARY
+ npx lerna ls --json | jq -r '.[] | "- **\(.name)** -> `v\(.version)`"' >> $GITHUB_STEP_SUMMARY
+
+ - name: Show Git Diff
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Package.json Changes" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo '```diff' >> $GITHUB_STEP_SUMMARY
+ git diff packages/*/package.json | head -100 >> $GITHUB_STEP_SUMMARY
+ echo '```' >> $GITHUB_STEP_SUMMARY
+
+ - name: Generate Changelog Preview
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Changelog Preview" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ npx lerna exec --concurrency 1 --stream -- \
+ 'conventional-changelog --preset angular --release-count 1 \
+ --commit-path $PWD --pkg $PWD/package.json' 2>/dev/null | \
+ sed 's/^[^:]*: //' >> $GITHUB_STEP_SUMMARY || echo "No changelog entries generated" >> $GITHUB_STEP_SUMMARY
+
+ - name: Show Conventional Commit Analysis
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Commit Analysis" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ breaking=$(git log --oneline --no-merges $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~50)..HEAD 2>/dev/null | grep -c "!" || echo "0")
+ features=$(git log --oneline --no-merges $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~50)..HEAD 2>/dev/null | grep -c "^[a-z0-9]* feat" || echo "0")
+ fixes=$(git log --oneline --no-merges $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~50)..HEAD 2>/dev/null | grep -c "^[a-z0-9]* fix" || echo "0")
+
+ echo "- **Breaking Changes**: $breaking" >> $GITHUB_STEP_SUMMARY
+ echo "- **Features**: $features" >> $GITHUB_STEP_SUMMARY
+ echo "- **Fixes**: $fixes" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ if [ "$breaking" -gt 0 ]; then
+ echo "**This release contains breaking changes!**" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ - name: Cleanup
+ if: always()
+ run: |
+ git reset --hard HEAD
+ git clean -fd
+
+ - name: Summary Footer
+ run: |
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "---" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**This is a preview only.** No changes have been committed or pushed." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "To proceed with this release:" >> $GITHUB_STEP_SUMMARY
+ echo "1. Run **Prepare Release** workflow" >> $GITHUB_STEP_SUMMARY
+ echo "2. Then run **Publish Packages** workflow" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/set-coverage.yml b/.github/workflows/set-coverage.yml
index 4e9c09a..c6be26c 100644
--- a/.github/workflows/set-coverage.yml
+++ b/.github/workflows/set-coverage.yml
@@ -15,52 +15,79 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- project: ['doubles.jest', 'doubles.sinon', 'core.unit', 'doubles.vitest', 'di.nestjs', 'di.inversify', 'unit']
+ project: ['cli', 'governance', 'changesets', 'json-schema-differ', 'types']
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: '18.x'
+ node-version: '22.x'
- - uses: actions/cache@v2
+ - uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
- - name: pnpm
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - name: Install dependencies
run: pnpm install --frozen-lockfile
+ - name: Build
+ run: pnpm build
+
- name: Create Coverage Directory
run: mkdir -p ${{ github.workspace }}/coverage
- name: Test
- run: pnpm --filter @contractual/${{ matrix.project }} run test
+ run: pnpm lerna run test --scope @contractual/${{ matrix.project }} --stream
+ continue-on-error: true
env:
- JEST_JUNIT_OUTPUT_NAME: ${{ matrix.project }}.xml
- JEST_JUNIT_OUTPUT_DIR: ${{ github.workspace }}/test-reports
- JUNIT_OUTPUT_NAME: ${{ matrix.project }}
- JUNIT_OUTPUT_DIR: ${{ github.workspace }}/test-reports
COVERAGE_DIR: ${{ github.workspace }}/coverage
COVERAGE_FILE: coverage-${{ matrix.project }}.xml
- - name: Tests Results
- uses: dorny/test-reporter@v1
- if: always()
- with:
- reporter: 'jest-junit'
- name: Tests Results (${{ matrix.project }})
- path: ${{ github.workspace }}/test-reports/${{ matrix.project }}.xml
- fail-on-error: false
-
- name: Upload Report to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
with:
name: codecov-umbrella
flags: ${{ matrix.project }}
token: ${{ secrets.CODECOV_TOKEN }}
- fail_ci_if_error: true
+ fail_ci_if_error: false
files: ${{ github.workspace }}/coverage/coverage-${{ matrix.project }}.xml
- verbose: true
\ No newline at end of file
+ verbose: true
+
+ e2e:
+ name: E2E Tests
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22.x'
+
+ - uses: actions/cache@v4
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9.15.4
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build
+ run: pnpm build
+
+ - name: Run E2E Tests
+ run: pnpm test:e2e
diff --git a/.github/workflows/tag-global.yml b/.github/workflows/tag-global.yml
index 68079f2..31f955e 100644
--- a/.github/workflows/tag-global.yml
+++ b/.github/workflows/tag-global.yml
@@ -24,10 +24,18 @@ jobs:
- name: Config Git
run: |
- git config --global user.email "omer.moradd@gmail.com"
- git config --global user.name "Omer Morad"
+ git config --global user.email "${{ github.actor }}@users.noreply.github.com"
+ git config --global user.name "${{ github.actor }}"
- name: Tag and Push
run: |
git tag -a ${{ inputs.tag_name }} -m "Tag Version ${{ inputs.tag_name }}"
- git push origin ${{ inputs.tag_name }}
\ No newline at end of file
+ git push origin ${{ inputs.tag_name }}
+
+ - name: Generate Summary
+ run: |
+ echo "## Tag Created" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Tag:** \`${{ inputs.tag_name }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Commit:** \`$(git rev-parse HEAD)\`" >> $GITHUB_STEP_SUMMARY
+ echo "**Branch:** \`$(git rev-parse --abbrev-ref HEAD)\`" >> $GITHUB_STEP_SUMMARY
diff --git a/.gitignore b/.gitignore
index 515c51e..885b5cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
+junit.xml
+
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
diff --git a/README.md b/README.md
index eeff71e..f21b5d8 100644
--- a/README.md
+++ b/README.md
@@ -1,173 +1,109 @@
-
Contractual
-
-Contractual is a tool for managing API and data schemas as structured contracts. It ensures that schemas
-are defined, versioned, and enforced across teams, whether for REST APIs, event-driven systems, or structured data
-exchanges.
-
-Common use cases include: \
-πΉ Keeping API Contracts in Sync Between Backend and Frontend \
-πΉ Generating Type-Safe Clients and Server Contracts \
-πΉ Preventing Breaking Changes and Detecting Schema Drift \
-πΉ Ensuring Consistency Between Backend and Data Teams \
-πΉ Generating Language-Specific Types from a Shared Contract
-
-By treating schemas as first-class entities, Contractual eliminates uncertainty at integration points, enabling backend,
-frontend, and data engineering teams to maintain predictable and enforceable APIs and structured data across the entire
-stack.
-
-> Initially built for the **Node.js and TypeScript ecosystem**, Contractual is planned to support additional
-> languages.
-
-## π In Practice
-
-### Install Contractual
-
-To get started, install the Contractual CLI globally:
-
-```bash
-npm i -g @contractual/cli
-```
-
-### Initialize Your Project
-
-Run the `init` command to scaffold a new project:
-
-```bash
-contractual init
-```
-
-This command creates the following project structure:
-
-```
-frontend/ # Your frontend application
-server/ # Your server application
-contractual/ # Contractual files
-βββ api.tsp # TypeSpec API definition
-βββ specs/ # OpenAPI auto-generated specs
-```
-
-> Contractual works seamlessly with **monorepos**, **monoliths**, and distributed repositories.
-
-### Define Your API
-
-Write your API definition in the `api.tsp` file. For example:
-
-```tsp
-import "@typespec/http";
-import "@typespec/openapi";
-import "@typespec/openapi3";
-
-using TypeSpec.Http;
-
-@service({
- title: "Petstore API",
-})
-namespace PetstoreAPI;
-
-model Pet {
- id: string;
- name: string;
-}
-
-@route("/pet")
-@post
-op addPet(@body body: Pet): Pet;
-```
-
-> You can experiment and validate your API definitions [using the TypeSpec playground](https://typespec.io/playground/)
-
-### Manage API Changes
-
-#### Save the Current State of Your API
-
-Run the `spec graduate` command to save the current state of your OpenAPI spec:
-
-```bash
-contractual spec graduate
-```
-
-This will generate a new OpenAPI (3.1.0) YAML file with versioning, enabling to track API changes over time. The
-updated structure will look like this:
-
-```
-contractual/
-βββ api.tsp # TypeSpec API definition
-βββ specs/ # OpenAPI auto-generated specs
-β βββ openapi-v1.0.0.yaml
-client/ # Generated API clients
-server/ # Server contracts
-e2e/ # Type-safe API-driven tests
-```
-
-> You can track API evolution and changes easily with clear, versioned OpenAPI specs.
-
-Hereβs a quick video showing how this works:
-
-
-

-
-
-### Generate Contracts
-
-Run the `contract generate` command to generate type-safe clients, server contracts, and updated OpenAPI specs:
-
-```bash
-contractual contract generate
-```
-
-This command creates:
-
-- **Type-safe client libraries** [using **ts-rest**](https://ts-rest.com), integrated with **Zod** for runtime
- validation.
-- **Server contracts** for frameworks like **Express**, **Fastify**, and **NestJS**.
-- **Updated OpenAPI specs**.
-
-Hereβs a short video showing contract generation in action:
-
-
-

-
-```
-
-## π Why Contractual?
-
-Maintaining the consistency of schemas across various services presents significant challenges. As systems evolve,
-type-definitions and schemas drift, unnoticed breaking changes occur, and different teams find it challenging to
-synchronize. APIs, event schemas, and structured data formats often become disconnected from their original intent,
-leading to brittle integrations, manual fixes, and unexpected failures.
-
-**Some of the biggest pain points teams face include:**
-
-- **Schema Drift & Misalignment:** APIs and data contracts become inconsistent across teams, leading to mismatches, broken integrations, and regressions.
-
-- **Untracked Changes & Breaking Updates:** Without tracking modifications, updates can unexpectedly break consumers, causing downtime and costly debugging.
-
-- **Scattered Schemas & Code Maintenance:** Outdated documentation and manually managed type definitions create unreliable integrations and make maintaining entity models error-prone.
-
-## π The Contract-First Approach
-Most teams take a **code-first** approach to API development, where schemas are generated after implementation. This often results in **misalignment between services, outdated documentation, and accidental breaking changes.** Backend teams define APIs, frontend teams consume them, and data engineers rely on structured data formatsβall of which can drift over time when schemas are an afterthought.
-
-A **contract-first** approach flips this process: schemas are designed before any implementation begins, ensuring that API structures, event definitions, and data formats remain stable and predictable. This approach allows teams to:
-
-- Define schemas upfront and enforce them as the single source of truth.
-
-- Track changes and prevent breaking updates before they impact consumers.
-
-- Generate type-safe clients and server contracts in multiple languages, reducing friction between teams.
-
-## π Roadmap
-
-Want to contribute? Check out the alpha version [Roadmap](https://github.com/contractual-dev/contractual/issues/8) and
-join the journey! π
-
-## β€οΈ Join the Community
-
-Contractual is open-source, and weβre looking for contributors to help shape its future, if youβre interested in
-collaborating, please reach out.
-
-π© **Feedback or Questions?** Reach out
-via [GitHub Discussions](https://github.com/contractual-dev/contractual/discussions).
-
-## π License
-
-Licensed under [MIT](LICENSE).
+
+
+
+
+Contractual
+
+
+Schema contract lifecycle for OpenAPI, JSON Schema, and AsyncAPI
+
+Linting β’ Breaking change detection β’ Versioning β’ Release automation
+
+
+
+
+
+
+
+Supported Formats: OpenAPI, JSON Schema, AsyncAPI
+
+
+## Features
+
+- **Structural Breaking Change Detection** - Compares specs against versioned snapshots using structural diffing, not string comparison. Catches removed fields, type changes, and endpoint deletions.
+
+- **Automated Versioning** - Changesets declare bump levels (major/minor/patch). `contractual version` consumes them, bumps versions, updates snapshots, and generates changelogs.
+
+- **CI Integration** - GitHub Action posts diff tables on PRs, auto-generates changesets, and opens Version PRs for release automation.
+
+- **Format Agnostic** - Works with OpenAPI, JSON Schema, and AsyncAPI. Custom linters and differs can be configured per contract.
+
+## Quick Example
+
+### Detect changes
+
+```bash
+$ contractual diff
+
+orders-api: 3 changes (2 breaking, 1 non-breaking) β suggested bump: major
+
+ BREAKING Removed endpoint GET /orders/{id}/details
+ BREAKING Changed type of field 'amount': string β number
+ non-breaking Added optional field 'tracking_url'
+```
+
+### Generate a changeset
+
+```bash
+$ contractual changeset
+
+? Bump type for orders-api: major
+? Summary: Remove deprecated endpoint, change amount type
+
+Wrote .contractual/changesets/fuzzy-lion-dances.md
+```
+
+### Bump versions
+
+```bash
+$ contractual version
+
+orders-api 1.4.2 β 2.0.0 (major)
+
+Updated .contractual/versions.json
+Updated CHANGELOG.md
+```
+
+## Installation
+
+```bash
+npm install -g @contractual/cli
+```
+
+Or with other package managers:
+
+```bash
+pnpm add -g @contractual/cli
+yarn global add @contractual/cli
+```
+
+## Getting Started
+
+1. **Initialize** - `contractual init` scans for specs and creates `contractual.yaml`
+2. **Lint** - `contractual lint` validates specs
+3. **Detect changes** - `contractual diff` shows all changes classified
+4. **CI gate** - `contractual breaking` fails if breaking changes exist
+5. **Version** - `contractual changeset` + `contractual version` for releases
+
+[β Full Quickstart Guide](https://contractual.dev/getting-started/quickstart)
+
+## Community
+
+- [Documentation](https://contractual.dev)
+- [GitHub Issues](https://github.com/contractual-dev/contractual/issues)
+
+## License
+
+[MIT](LICENSE)
diff --git a/contract-generate.gif b/contract-generate.gif
deleted file mode 100644
index acc7946..0000000
Binary files a/contract-generate.gif and /dev/null differ
diff --git a/e2e/.gitignore b/e2e/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/e2e/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/e2e/cli-basic/cli-install.test.ts b/e2e/cli-basic/cli-install.test.ts
new file mode 100644
index 0000000..3ebfed7
--- /dev/null
+++ b/e2e/cli-basic/cli-install.test.ts
@@ -0,0 +1,79 @@
+import { execSync } from 'node:child_process';
+import { describe, test, expect } from 'vitest';
+
+function run(command: string): string {
+ return execSync(command, {
+ encoding: 'utf-8',
+ stdio: ['pipe', 'pipe', 'pipe'],
+ env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },
+ });
+}
+
+describe('CLI Installation and Basic Commands', () => {
+ test('contractual binary is available after npm install', () => {
+ const result = run('npx @contractual/cli --version');
+ expect(result).toMatch(/\d+\.\d+\.\d+/);
+ });
+
+ test('contractual --help shows available commands', () => {
+ const result = run('npx @contractual/cli --help');
+ expect(result).toContain('init');
+ expect(result).toContain('lint');
+ expect(result).toContain('diff');
+ expect(result).toContain('breaking');
+ expect(result).toContain('changeset');
+ expect(result).toContain('version');
+ expect(result).toContain('status');
+ expect(result).toContain('contract');
+ expect(result).toContain('pre');
+ });
+
+ test('contractual init --help shows init options', () => {
+ const result = run('npx @contractual/cli init --help');
+ expect(result.toLowerCase()).toContain('initialize');
+ });
+
+ test('contractual lint --help shows lint options', () => {
+ const result = run('npx @contractual/cli lint --help');
+ expect(result).toContain('--format');
+ });
+
+ test('contractual breaking --help shows breaking options', () => {
+ const result = run('npx @contractual/cli breaking --help');
+ expect(result).toContain('--format');
+ });
+
+ test('contractual diff --help shows diff options', () => {
+ const result = run('npx @contractual/cli diff --help');
+ expect(result).toContain('--format');
+ expect(result).toContain('--severity');
+ expect(result).toContain('--verbose');
+ });
+
+ test('contractual contract --help shows subcommands', () => {
+ const result = run('npx @contractual/cli contract --help');
+ expect(result).toContain('add');
+ expect(result).toContain('list');
+ });
+
+ test('contractual contract add --help shows add options', () => {
+ const result = run('npx @contractual/cli contract add --help');
+ expect(result).toContain('--name');
+ expect(result).toContain('--type');
+ expect(result).toContain('--path');
+ });
+
+ test('contractual pre --help shows subcommands', () => {
+ const result = run('npx @contractual/cli pre --help');
+ expect(result).toContain('enter');
+ expect(result).toContain('exit');
+ expect(result).toContain('status');
+ });
+
+ test('contractual version --help shows version options', () => {
+ const result = run('npx @contractual/cli version --help');
+ expect(result).toContain('--dry-run');
+ expect(result).toContain('--json');
+ expect(result).toContain('--yes');
+ });
+});
diff --git a/e2e/cli-basic/package.json b/e2e/cli-basic/package.json
new file mode 100644
index 0000000..f907462
--- /dev/null
+++ b/e2e/cli-basic/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "contractual-e2e-cli-basic",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "dependencies": {
+ "@contractual/cli": "e2e"
+ },
+ "devDependencies": {
+ "@types/node": "^22.10.2",
+ "vitest": "^3.0.3",
+ "typescript": "~5.7.2"
+ },
+ "scripts": {
+ "test": "vitest run"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+}
diff --git a/e2e/cli-basic/tsconfig.json b/e2e/cli-basic/tsconfig.json
new file mode 100644
index 0000000..18f6945
--- /dev/null
+++ b/e2e/cli-basic/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "rootDir": "."
+ },
+ "include": ["./**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/e2e/cli-basic/vitest.config.ts b/e2e/cli-basic/vitest.config.ts
new file mode 100644
index 0000000..df1ce1b
--- /dev/null
+++ b/e2e/cli-basic/vitest.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['**/*.test.ts'],
+ testTimeout: 30_000,
+ globals: true,
+ },
+});
diff --git a/e2e/cli-lifecycle/fixtures/json-schema/order-base.json b/e2e/cli-lifecycle/fixtures/json-schema/order-base.json
new file mode 100644
index 0000000..cec8f1b
--- /dev/null
+++ b/e2e/cli-lifecycle/fixtures/json-schema/order-base.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/e2e/cli-lifecycle/fixtures/json-schema/order-field-removed.json b/e2e/cli-lifecycle/fixtures/json-schema/order-field-removed.json
new file mode 100644
index 0000000..4b8cb38
--- /dev/null
+++ b/e2e/cli-lifecycle/fixtures/json-schema/order-field-removed.json
@@ -0,0 +1,84 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/e2e/cli-lifecycle/fixtures/json-schema/order-optional-field-added.json b/e2e/cli-lifecycle/fixtures/json-schema/order-optional-field-added.json
new file mode 100644
index 0000000..bb1166e
--- /dev/null
+++ b/e2e/cli-lifecycle/fixtures/json-schema/order-optional-field-added.json
@@ -0,0 +1,93 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ },
+ "tracking_number": {
+ "type": "string",
+ "description": "Shipment tracking number"
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/e2e/cli-lifecycle/full-lifecycle.test.ts b/e2e/cli-lifecycle/full-lifecycle.test.ts
new file mode 100644
index 0000000..63189ee
--- /dev/null
+++ b/e2e/cli-lifecycle/full-lifecycle.test.ts
@@ -0,0 +1,306 @@
+import { describe, test, expect, afterEach } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ run,
+ setupRepoWithConfig,
+ copyFixture,
+ writeFile,
+ readJSON,
+ fileExists,
+ listFiles,
+} from './helpers.js';
+
+describe('Full CLI Lifecycle (installed from Verdaccio)', () => {
+ let repo: { dir: string; cleanup: () => void };
+
+ afterEach(() => {
+ repo?.cleanup();
+ });
+
+ test('init detects JSON Schema and creates config', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.schema.json'));
+
+ const result = run('init', dir);
+ expect(result.exitCode).toBe(0);
+ expect(fileExists(dir, 'contractual.yaml')).toBe(true);
+ expect(fileExists(dir, '.contractual/versions.json')).toBe(true);
+ });
+
+ test('status shows contract versions', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.2.3', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order/);
+ expect(result.stdout).toMatch(/1\.2\.3/);
+ });
+
+ test('breaking detects field removal', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+ });
+
+ test('changeset creates a changeset file for breaking change', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThan(0);
+ });
+
+ test('complete lifecycle: changeset -> version', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ // Setup with a JSON Schema contract
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Make a breaking change
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ // Run changeset
+ const changesetResult = run('changeset', dir);
+ expect(changesetResult.exitCode).toBe(0);
+
+ // Verify changeset exists
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThan(0);
+
+ // Run version
+ const versionResult = run('version', dir);
+ expect(versionResult.exitCode).toBe(0);
+ expect(versionResult.stdout).toMatch(/2\.0\.0/);
+
+ // Verify version updated
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order'].version).toBe('2.0.0');
+ });
+
+ test('diff shows changes between spec and snapshot', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.contracts).toBeDefined();
+ expect(parsed.contracts.order).toBeDefined();
+ expect(parsed.contracts.order.changes.length).toBeGreaterThan(0);
+ });
+
+ test('contract list shows configured contracts', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('contract list --json', dir);
+ expect(result.exitCode).toBe(0);
+ const contracts = JSON.parse(result.stdout);
+ expect(Array.isArray(contracts)).toBe(true);
+ expect(contracts[0].name).toBe('order');
+ });
+
+ test('contract add adds new contract to config', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('contract add --name user --type json-schema --path schemas/user.json -y', dir);
+ expect(result.exitCode).toBe(0);
+
+ const listResult = run('contract list --json', dir);
+ const contracts = JSON.parse(listResult.stdout);
+ expect(contracts.length).toBe(2);
+ expect(contracts.find((c: { name: string }) => c.name === 'user')).toBeDefined();
+ });
+
+ test('pre enter/exit manages pre-release mode', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Enter pre-release mode
+ const enterResult = run('pre enter beta', dir);
+ expect(enterResult.exitCode).toBe(0);
+ expect(fileExists(dir, '.contractual/pre.json')).toBe(true);
+
+ // Check status
+ const statusResult = run('pre status', dir);
+ expect(statusResult.exitCode).toBe(0);
+ expect(statusResult.stdout).toMatch(/beta/i);
+
+ // Exit pre-release mode
+ const exitResult = run('pre exit', dir);
+ expect(exitResult.exitCode).toBe(0);
+ expect(fileExists(dir, '.contractual/pre.json')).toBe(false);
+ });
+
+ test('version --dry-run shows preview without changes', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create changeset
+ writeFile(
+ dir,
+ '.contractual/changesets/test.md',
+ `---
+"order": minor
+---
+
+Test change
+`
+ );
+
+ const result = run('version --dry-run', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify version NOT changed
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order'].version).toBe('1.0.0');
+ });
+
+ test('version --json outputs structured result', () => {
+ repo = createTempRepo();
+ const { dir } = repo;
+
+ setupRepoWithConfig(dir, [{ name: 'order', type: 'json-schema', path: 'schemas/order.json' }]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, '.contractual/snapshots/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create changeset
+ writeFile(
+ dir,
+ '.contractual/changesets/test.md',
+ `---
+"order": patch
+---
+
+Bug fix
+`
+ );
+
+ const result = run('version --json', dir);
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(output.bumps).toBeDefined();
+ expect(Array.isArray(output.bumps)).toBe(true);
+ });
+});
diff --git a/e2e/cli-lifecycle/helpers.ts b/e2e/cli-lifecycle/helpers.ts
new file mode 100644
index 0000000..b844588
--- /dev/null
+++ b/e2e/cli-lifecycle/helpers.ts
@@ -0,0 +1,167 @@
+import { execSync } from 'node:child_process';
+import {
+ mkdtempSync,
+ mkdirSync,
+ writeFileSync,
+ readFileSync,
+ existsSync,
+ rmSync,
+ readdirSync,
+ cpSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
+
+/** Path to the fixtures directory */
+const FIXTURES_DIR = new URL('./fixtures', import.meta.url).pathname;
+
+/**
+ * Create a temp directory that auto-cleans after test
+ */
+export function createTempRepo(): { dir: string; cleanup: () => void } {
+ const dir = mkdtempSync(path.join(tmpdir(), 'contractual-e2e-'));
+
+ return {
+ dir,
+ cleanup: () => {
+ try {
+ rmSync(dir, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ },
+ };
+}
+
+/**
+ * Run a contractual CLI command in the given directory
+ */
+export function run(
+ command: string,
+ cwd: string,
+ options?: { expectFail?: boolean }
+): { stdout: string; stderr: string; exitCode: number } {
+ const fullCmd = `npx @contractual/cli ${command}`;
+
+ try {
+ const stdout = execSync(fullCmd, {
+ cwd,
+ encoding: 'utf-8',
+ stdio: ['pipe', 'pipe', 'pipe'],
+ env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },
+ });
+ return { stdout, stderr: '', exitCode: 0 };
+ } catch (err: unknown) {
+ const error = err as { stdout?: string; stderr?: string; status?: number };
+ if (!options?.expectFail) {
+ throw new Error(
+ `Command failed: ${fullCmd}\n` +
+ `Exit code: ${error.status}\n` +
+ `stdout: ${error.stdout}\n` +
+ `stderr: ${error.stderr}`
+ );
+ }
+ return {
+ stdout: error.stdout ?? '',
+ stderr: error.stderr ?? '',
+ exitCode: error.status ?? 1,
+ };
+ }
+}
+
+/**
+ * Copy a fixture file to the temp repo
+ */
+export function copyFixture(fixturePath: string, destPath: string): void {
+ const src = path.join(FIXTURES_DIR, fixturePath);
+ const destDir = path.dirname(destPath);
+
+ if (!existsSync(destDir)) {
+ mkdirSync(destDir, { recursive: true });
+ }
+
+ cpSync(src, destPath);
+}
+
+/**
+ * Write a file in the temp repo
+ */
+export function writeFile(repoDir: string, relativePath: string, content: string): void {
+ const fullPath = path.join(repoDir, relativePath);
+ const dir = path.dirname(fullPath);
+
+ if (!existsSync(dir)) {
+ mkdirSync(dir, { recursive: true });
+ }
+
+ writeFileSync(fullPath, content);
+}
+
+/**
+ * Read a file from the temp repo
+ */
+export function readFile(repoDir: string, relativePath: string): string {
+ return readFileSync(path.join(repoDir, relativePath), 'utf-8');
+}
+
+/**
+ * Check if a file exists in the temp repo
+ */
+export function fileExists(repoDir: string, relativePath: string): boolean {
+ return existsSync(path.join(repoDir, relativePath));
+}
+
+/**
+ * List files in a directory within the temp repo
+ */
+export function listFiles(repoDir: string, relativePath: string): string[] {
+ const fullPath = path.join(repoDir, relativePath);
+ if (!existsSync(fullPath)) return [];
+ return readdirSync(fullPath);
+}
+
+/**
+ * Read and parse JSON from the temp repo
+ */
+export function readJSON(repoDir: string, relativePath: string): unknown {
+ return JSON.parse(readFile(repoDir, relativePath));
+}
+
+/**
+ * Read and parse YAML from the temp repo
+ */
+export function readYAML(repoDir: string, relativePath: string): unknown {
+ const content = readFile(repoDir, relativePath);
+ return parseYaml(content);
+}
+
+/**
+ * Setup a repo with a contractual.yaml config and .contractual directory
+ */
+export function setupRepoWithConfig(
+ repoDir: string,
+ contracts: Array<{
+ name: string;
+ type: string;
+ path: string;
+ }>
+): void {
+ const config = {
+ contracts: contracts.map((c) => ({
+ name: c.name,
+ type: c.type,
+ path: c.path,
+ })),
+ };
+
+ writeFile(repoDir, 'contractual.yaml', stringifyYaml(config));
+
+ // Create .contractual directory structure
+ mkdirSync(path.join(repoDir, '.contractual/changesets'), { recursive: true });
+ mkdirSync(path.join(repoDir, '.contractual/snapshots'), { recursive: true });
+
+ if (!fileExists(repoDir, '.contractual/versions.json')) {
+ writeFile(repoDir, '.contractual/versions.json', '{}');
+ }
+}
diff --git a/e2e/cli-lifecycle/package.json b/e2e/cli-lifecycle/package.json
new file mode 100644
index 0000000..78d3385
--- /dev/null
+++ b/e2e/cli-lifecycle/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "contractual-e2e-cli-lifecycle",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "dependencies": {
+ "@contractual/cli": "e2e"
+ },
+ "devDependencies": {
+ "@types/node": "^22.10.2",
+ "vitest": "^3.0.3",
+ "typescript": "~5.7.2",
+ "yaml": "^2.8.2"
+ },
+ "scripts": {
+ "test": "vitest run"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+}
diff --git a/e2e/cli-lifecycle/tsconfig.json b/e2e/cli-lifecycle/tsconfig.json
new file mode 100644
index 0000000..18f6945
--- /dev/null
+++ b/e2e/cli-lifecycle/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "rootDir": "."
+ },
+ "include": ["./**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/e2e/cli-lifecycle/vitest.config.ts b/e2e/cli-lifecycle/vitest.config.ts
new file mode 100644
index 0000000..795884b
--- /dev/null
+++ b/e2e/cli-lifecycle/vitest.config.ts
@@ -0,0 +1,10 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['**/*.test.ts'],
+ testTimeout: 60_000,
+ hookTimeout: 30_000,
+ globals: true,
+ },
+});
diff --git a/e2e/config.yaml b/e2e/config.yaml
new file mode 100644
index 0000000..f74202d
--- /dev/null
+++ b/e2e/config.yaml
@@ -0,0 +1,24 @@
+storage: /verdaccio/storage
+
+uplinks:
+ npmjs:
+ url: https://registry.npmjs.org/
+
+packages:
+ '@contractual/*':
+ access: $all
+ publish: $all
+ unpublish: $all
+ '**':
+ access: $all
+ publish: $all
+ proxy: npmjs
+
+auth:
+ htpasswd:
+ file: ./htpasswd
+ algorithm: bcrypt
+ rounds: 10
+
+logs:
+ - { type: stdout, format: pretty, level: http }
diff --git a/e2e/packages-import/imports.test.ts b/e2e/packages-import/imports.test.ts
new file mode 100644
index 0000000..4b247a1
--- /dev/null
+++ b/e2e/packages-import/imports.test.ts
@@ -0,0 +1,38 @@
+import { describe, test, expect } from 'vitest';
+
+describe('Package Imports (ESM)', () => {
+ test('@contractual/types exports are defined', async () => {
+ const types = await import('@contractual/types');
+ // TypeScript type check - if this compiles, types are exported correctly
+ expect(types).toBeDefined();
+ });
+
+ test('@contractual/changesets exports versioning utilities', async () => {
+ const changesets = await import('@contractual/changesets');
+ expect(changesets).toBeDefined();
+ // Check for key exports
+ expect(typeof changesets).toBe('object');
+ });
+
+ test('@contractual/governance exports are available', async () => {
+ const governance = await import('@contractual/governance');
+ expect(governance).toBeDefined();
+ expect(typeof governance).toBe('object');
+ });
+
+ test('@contractual/differs.json-schema exports differ', async () => {
+ const differ = await import('@contractual/differs.json-schema');
+ expect(differ).toBeDefined();
+ expect(typeof differ).toBe('object');
+ });
+
+ test('@contractual/governance/linters subpath export works', async () => {
+ const linters = await import('@contractual/governance/linters');
+ expect(linters).toBeDefined();
+ });
+
+ test('@contractual/governance/differs subpath export works', async () => {
+ const differs = await import('@contractual/governance/differs');
+ expect(differs).toBeDefined();
+ });
+});
diff --git a/e2e/packages-import/package.json b/e2e/packages-import/package.json
new file mode 100644
index 0000000..ee0f6d8
--- /dev/null
+++ b/e2e/packages-import/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "contractual-e2e-packages-import",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "dependencies": {
+ "@contractual/types": "e2e",
+ "@contractual/changesets": "e2e",
+ "@contractual/governance": "e2e",
+ "@contractual/differs.json-schema": "e2e"
+ },
+ "devDependencies": {
+ "@types/node": "^22.10.2",
+ "vitest": "^3.0.3",
+ "typescript": "~5.7.2"
+ },
+ "scripts": {
+ "test": "tsc --noEmit && vitest run"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+}
diff --git a/e2e/packages-import/tsconfig.json b/e2e/packages-import/tsconfig.json
new file mode 100644
index 0000000..18f6945
--- /dev/null
+++ b/e2e/packages-import/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "rootDir": "."
+ },
+ "include": ["./**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/e2e/packages-import/vitest.config.ts b/e2e/packages-import/vitest.config.ts
new file mode 100644
index 0000000..df1ce1b
--- /dev/null
+++ b/e2e/packages-import/vitest.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['**/*.test.ts'],
+ testTimeout: 30_000,
+ globals: true,
+ },
+});
diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json
new file mode 100644
index 0000000..791b27e
--- /dev/null
+++ b/e2e/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "esModuleInterop": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "resolveJsonModule": true
+ },
+ "exclude": ["node_modules", "**/node_modules"]
+}
diff --git a/lerna.json b/lerna.json
new file mode 100644
index 0000000..686ebce
--- /dev/null
+++ b/lerna.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "node_modules/lerna/schemas/lerna-schema.json",
+ "version": "independent",
+ "command": {
+ "publish": {
+ "registry": "https://registry.npmjs.org/",
+ "allowBranch": [
+ "master",
+ "next"
+ ],
+ "message": "chore(*): release packages [skip ci]",
+ "conventionalCommits": true
+ },
+ "version": {
+ "allowBranch": [
+ "master",
+ "next"
+ ],
+ "message": "chore(*): version packages [skip ci]",
+ "conventionalCommits": true
+ }
+ },
+ "npmClient": "pnpm",
+ "packages": [
+ "packages/*"
+ ]
+}
diff --git a/local-e2e.docker-compose.yaml b/local-e2e.docker-compose.yaml
new file mode 100644
index 0000000..c205944
--- /dev/null
+++ b/local-e2e.docker-compose.yaml
@@ -0,0 +1,32 @@
+name: contractual-local-e2e
+
+services:
+ verdaccio:
+ image: verdaccio/verdaccio
+ ports:
+ - '4873:4873'
+ volumes:
+ - ./e2e/config.yaml:/verdaccio/conf/config.yaml
+ - verdaccio-storage:/verdaccio/storage
+ networks:
+ - e2e-network
+
+ executor:
+ image: node:22-alpine
+ working_dir: /workspace
+ volumes:
+ - .:/workspace
+ command: ['tail', '-f', '/dev/null']
+ networks:
+ - e2e-network
+ depends_on:
+ - verdaccio
+ environment:
+ - NPM_CONFIG_PROVENANCE=false
+
+networks:
+ e2e-network:
+ driver: bridge
+
+volumes:
+ verdaccio-storage:
diff --git a/logo.png b/logo.png
new file mode 100644
index 0000000..cde1ab0
Binary files /dev/null and b/logo.png differ
diff --git a/package.json b/package.json
index 0cec923..14a20c1 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"url": "https://github.com/contractual-dev/contractual.git"
},
"engines": {
- "node": "^18.12.0 || >=20.0.0"
+ "node": ">=20.0.0"
},
"bugs": {
"url": "https://github.com/contractual-dev/contractual.git"
@@ -22,60 +22,42 @@
}
],
"scripts": {
- "build": "pnpm -r run build",
- "tester": "pnpm -r run test",
- "lint": "pnpm -r run lint",
- "prepare": "husky"
+ "build": "pnpm lerna run build --stream",
+ "build:watch": "pnpm -r run build:watch",
+ "test": "pnpm lerna run test --stream",
+ "test:e2e": "vitest run --config vitest.config.e2e.ts",
+ "test:e2e:watch": "vitest --config vitest.config.e2e.ts",
+ "lint": "pnpm lerna run lint --parallel",
+ "prepare": "husky",
+ "version:preview": "lerna changed --json | jq -r '.[] | \"\\(.name) β v\\(.version)\"'",
+ "publish:dry": "lerna publish from-package --yes --no-git-reset --dry-run",
+ "e2e:verdaccio:up": "docker compose -f local-e2e.docker-compose.yaml up -d",
+ "e2e:verdaccio:down": "docker compose -f local-e2e.docker-compose.yaml down -v"
},
- "dependencies": {
- "@manypkg/cli": "^0.21.4",
+ "devDependencies": {
"@types/node": "^22.10.2",
+ "lerna": "^8.2.3",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
- "@vitest/coverage-c8": "^0.33.0",
- "@vitest/coverage-v8": "3.0.3",
- "braces": "3.0.3",
+ "@vitest/coverage-v8": "^3.0.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.0.1",
- "follow-redirects": "1.15.6",
- "ip": "2.0.1",
- "lerna": "^7.3.1",
+ "husky": "^8.0.3",
+ "json-schema-typed": "^8.0.2",
"lint-staged": "^14.0.1",
- "madge": "^7.0.0",
- "micromatch": "4.0.8",
"prettier": "^3.2.5",
"rimraf": "^5.0.5",
- "rxjs": "^7.8.1",
- "tar": "6.2.0",
- "ts-jest": "^29.1.3",
- "ts-node": "^10.9.1",
"typescript": "~5.7.2",
- "vitest": "^3.0.3"
+ "vitest": "^3.0.3",
+ "yaml": "^2.8.2"
},
- "workspaces": [
- "packages/generators/*",
- "packages/providers/*",
- "packages/types/*",
- "packages/*"
- ],
"lint-staged": {
"*.ts": [
"eslint --ext .ts --fix"
]
},
- "jest-junit": {
- "outputDirectory": "test-reports",
- "ancestorSeparator": " βΊ ",
- "uniqueOutputName": "true",
- "suiteNameTemplate": "{filepath}",
- "classNameTemplate": "{classname}",
- "titleTemplate": "{title}"
- },
- "packageManager": "pnpm@9.15.4",
- "devDependencies": {
- "husky": "^8.0.3"
- }
+ "packageManager": "pnpm@9.15.4"
}
diff --git a/packages/changesets/changesets/consume.ts b/packages/changesets/changesets/consume.ts
new file mode 100644
index 0000000..e7ee36b
--- /dev/null
+++ b/packages/changesets/changesets/consume.ts
@@ -0,0 +1,110 @@
+/**
+ * Changeset consumption utilities
+ * Processes changesets for the version command
+ */
+
+import type { BumpType, ChangesetFile } from '@contractual/types';
+
+/**
+ * Bump type priority for comparison (higher = more significant)
+ */
+const BUMP_PRIORITY: Readonly> = {
+ major: 3,
+ minor: 2,
+ patch: 1,
+} as const;
+
+/**
+ * Compare two bump types and return the higher priority one
+ */
+function higherBump(a: BumpType, b: BumpType): BumpType {
+ return BUMP_PRIORITY[a] >= BUMP_PRIORITY[b] ? a : b;
+}
+
+/**
+ * Aggregate bumps from multiple changesets
+ * For each contract, the highest bump type wins
+ *
+ * @param changesets - Array of parsed changeset files
+ * @returns Map of contract name to aggregated bump type
+ */
+export function aggregateBumps(
+ changesets: readonly ChangesetFile[]
+): Record {
+ const aggregated: Record = {};
+
+ for (const changeset of changesets) {
+ for (const [contract, bump] of Object.entries(changeset.bumps)) {
+ const existing = aggregated[contract];
+ aggregated[contract] = existing ? higherBump(existing, bump) : bump;
+ }
+ }
+
+ return aggregated;
+}
+
+/**
+ * Extract the markdown section for a specific contract from changesets
+ * Combines all change descriptions for the contract across all changesets
+ *
+ * @param changesets - Array of parsed changeset files
+ * @param contractName - Name of the contract to extract changes for
+ * @returns Combined markdown content for the contract
+ */
+export function extractContractChanges(
+ changesets: readonly ChangesetFile[],
+ contractName: string
+): string {
+ const sections: string[] = [];
+
+ for (const changeset of changesets) {
+ // Only process changesets that affect this contract
+ if (!(contractName in changeset.bumps)) {
+ continue;
+ }
+
+ // Extract the section for this contract from the body
+ const section = extractSectionFromBody(changeset.body, contractName);
+ if (section) {
+ sections.push(section);
+ }
+ }
+
+ return sections.join('\n\n');
+}
+
+/**
+ * Extract a contract's section from a changeset body
+ * Looks for ## ContractName and extracts content until the next ## or end
+ */
+function extractSectionFromBody(body: string, contractName: string): string {
+ const lines = body.split('\n');
+ const headerPattern = new RegExp(`^##\\s+${escapeRegex(contractName)}\\s*$`);
+
+ let inSection = false;
+ const sectionLines: string[] = [];
+
+ for (const line of lines) {
+ if (headerPattern.test(line)) {
+ inSection = true;
+ continue;
+ }
+
+ if (inSection) {
+ // Check if we've hit the next section
+ if (line.startsWith('## ')) {
+ break;
+ }
+ sectionLines.push(line);
+ }
+ }
+
+ return sectionLines.join('\n').trim();
+}
+
+/**
+ * Escape special regex characters in a string
+ */
+function escapeRegex(str: string): string {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
diff --git a/packages/changesets/changesets/create.ts b/packages/changesets/changesets/create.ts
new file mode 100644
index 0000000..b2801ea
--- /dev/null
+++ b/packages/changesets/changesets/create.ts
@@ -0,0 +1,101 @@
+/**
+ * Changeset creation utilities
+ * Creates changeset files from diff results
+ */
+
+import type { DiffResult, BumpType, ChangeSeverity } from '@contractual/types';
+import { generateChangesetName } from './naming.js';
+
+/**
+ * Result of creating a changeset file
+ */
+export interface CreateChangesetResult {
+ /** Generated filename (e.g., "brave-tigers-fly.md") */
+ filename: string;
+ /** Full content of the changeset file including frontmatter and body */
+ content: string;
+}
+
+/**
+ * Severity label mapping for display purposes
+ */
+const SEVERITY_LABELS: Record = {
+ breaking: 'BREAKING',
+ 'non-breaking': 'minor',
+ patch: 'patch',
+ unknown: 'unknown',
+} as const;
+
+/**
+ * Map change severity to display label
+ */
+function severityToLabel(severity: ChangeSeverity): string {
+ return SEVERITY_LABELS[severity];
+}
+
+/**
+ * Determine the suggested bump type for a contract based on its changes
+ */
+function determineBumpType(result: DiffResult): BumpType {
+ if (result.summary.breaking > 0) {
+ return 'major';
+ }
+ if (result.summary.nonBreaking > 0) {
+ return 'minor';
+ }
+ return 'patch';
+}
+
+/**
+ * Create a changeset from diff results
+ *
+ * @param results - Array of diff results from comparing specs
+ * @param overrides - Optional map of contract name to bump type overrides
+ * @returns Object with filename and content for the changeset file
+ */
+export function createChangeset(
+ results: DiffResult[],
+ overrides?: Readonly>
+): CreateChangesetResult {
+ const filename = `${generateChangesetName()}.md`;
+
+ // Build YAML frontmatter
+ const bumps: Record = {};
+ for (const result of results) {
+ if (result.changes.length === 0) {
+ continue;
+ }
+ const suggestedBump = determineBumpType(result);
+ bumps[result.contract] = overrides?.[result.contract] ?? suggestedBump;
+ }
+
+ // Generate YAML frontmatter
+ const yamlLines = Object.entries(bumps).map(
+ ([contract, bump]) => `"${contract}": ${bump}`
+ );
+ const frontmatter = `---\n${yamlLines.join('\n')}\n---`;
+
+ // Generate markdown body with changes grouped by contract
+ const bodyParts: string[] = [];
+
+ for (const result of results) {
+ if (result.changes.length === 0) {
+ continue;
+ }
+
+ bodyParts.push(`## ${result.contract}`);
+ bodyParts.push('');
+
+ for (const change of result.changes) {
+ const label = severityToLabel(change.severity);
+ bodyParts.push(`- **[${label}]** ${change.message}`);
+ }
+
+ bodyParts.push('');
+ }
+
+ const body = bodyParts.join('\n').trim();
+ const content = `${frontmatter}\n\n${body}\n`;
+
+ return { filename, content };
+}
diff --git a/packages/changesets/changesets/index.ts b/packages/changesets/changesets/index.ts
new file mode 100644
index 0000000..dbc6070
--- /dev/null
+++ b/packages/changesets/changesets/index.ts
@@ -0,0 +1,4 @@
+export * from './naming.js';
+export * from './create.js';
+export * from './read.js';
+export * from './consume.js';
diff --git a/packages/changesets/changesets/naming.ts b/packages/changesets/changesets/naming.ts
new file mode 100644
index 0000000..b849edd
--- /dev/null
+++ b/packages/changesets/changesets/naming.ts
@@ -0,0 +1,126 @@
+/**
+ * Changeset naming utilities
+ * Generates random three-word names for changeset files
+ */
+
+const ADJECTIVES = [
+ 'brave',
+ 'calm',
+ 'eager',
+ 'fancy',
+ 'gentle',
+ 'happy',
+ 'jolly',
+ 'kind',
+ 'lively',
+ 'mighty',
+ 'noble',
+ 'proud',
+ 'quick',
+ 'ready',
+ 'sharp',
+ 'swift',
+ 'tender',
+ 'vivid',
+ 'warm',
+ 'zesty',
+] as const;
+
+const NOUNS = [
+ 'bears',
+ 'cats',
+ 'dogs',
+ 'eagles',
+ 'foxes',
+ 'geese',
+ 'hawks',
+ 'ibis',
+ 'jays',
+ 'kites',
+ 'lions',
+ 'mice',
+ 'newts',
+ 'owls',
+ 'pandas',
+ 'quails',
+ 'ravens',
+ 'seals',
+ 'tigers',
+ 'wolves',
+] as const;
+
+const VERBS = [
+ 'fly',
+ 'run',
+ 'jump',
+ 'swim',
+ 'dance',
+ 'sing',
+ 'play',
+ 'rest',
+ 'hunt',
+ 'roam',
+ 'climb',
+ 'glide',
+ 'soar',
+ 'leap',
+ 'dash',
+ 'drift',
+ 'march',
+ 'prowl',
+ 'race',
+ 'sprint',
+] as const;
+
+/**
+ * Get a random element from an array
+ * @throws {Error} If the array is empty
+ */
+function randomElement(array: readonly T[]): T {
+ if (array.length === 0) {
+ throw new Error('Cannot get random element from empty array');
+ }
+ const index = Math.floor(Math.random() * array.length);
+ const element = array[index];
+ // This assertion is safe because we've checked array.length > 0 and index is within bounds
+ return element as T;
+}
+
+/**
+ * Generate a random three-word changeset name
+ * Format: adjective-noun-verb (e.g., "brave-tigers-fly")
+ */
+export function generateChangesetName(): string {
+ const adjective = randomElement(ADJECTIVES);
+ const noun = randomElement(NOUNS);
+ const verb = randomElement(VERBS);
+
+ return `${adjective}-${noun}-${verb}`;
+}
+
+/**
+ * Generate a unique changeset name that doesn't collide with existing names
+ * Retries with new random names until a unique one is found
+ *
+ * @param existingNames - Array of existing changeset names to avoid
+ * @param maxRetries - Maximum number of retries before giving up (default: 100)
+ * @returns A unique changeset name
+ * @throws Error if unable to generate a unique name after max retries
+ */
+export function generateUniqueChangesetName(
+ existingNames: string[],
+ maxRetries = 100
+): string {
+ const existingSet = new Set(existingNames);
+
+ for (let i = 0; i < maxRetries; i++) {
+ const name = generateChangesetName();
+ if (!existingSet.has(name)) {
+ return name;
+ }
+ }
+
+ // Fallback: append timestamp to ensure uniqueness
+ const baseName = generateChangesetName();
+ return `${baseName}-${Date.now()}`;
+}
diff --git a/packages/changesets/changesets/read.ts b/packages/changesets/changesets/read.ts
new file mode 100644
index 0000000..441322b
--- /dev/null
+++ b/packages/changesets/changesets/read.ts
@@ -0,0 +1,141 @@
+/**
+ * Changeset reading and parsing utilities
+ * Parses changeset files from the .contractual/changesets directory
+ */
+
+import { readdir, readFile } from 'node:fs/promises';
+import { join } from 'node:path';
+import { parse as parseYaml } from 'yaml';
+import type { BumpType, ChangesetFile } from '@contractual/types';
+
+/**
+ * Valid bump type values
+ */
+const VALID_BUMP_TYPES = ['major', 'minor', 'patch'] as const;
+
+/**
+ * Error thrown when parsing a changeset file fails
+ */
+export class ChangesetParseError extends Error {
+ constructor(
+ message: string,
+ public readonly filename?: string
+ ) {
+ super(filename ? `Failed to parse changeset "${filename}": ${message}` : message);
+ this.name = 'ChangesetParseError';
+ }
+}
+
+/**
+ * Parsed changeset content (before wrapping with filename)
+ */
+export interface ParsedChangesetContent {
+ /** Map of contract name to bump type */
+ bumps: Record;
+ /** Markdown body with change descriptions */
+ body: string;
+}
+
+/**
+ * Validate that a value is a valid bump type
+ */
+function isValidBumpType(value: unknown): value is BumpType {
+ return VALID_BUMP_TYPES.includes(value as BumpType);
+}
+
+/**
+ * Parse a changeset file content into its components
+ *
+ * @param content - Raw content of the changeset file
+ * @returns Parsed bumps and body
+ * @throws {ChangesetParseError} If the content is malformed
+ */
+export function parseChangeset(content: string): ParsedChangesetContent {
+ const trimmed = content.trim();
+
+ // Check for frontmatter delimiter
+ if (!trimmed.startsWith('---')) {
+ throw new ChangesetParseError('Changeset must start with YAML frontmatter (---)');
+ }
+
+ // Find the closing frontmatter delimiter
+ const secondDelimiter = trimmed.indexOf('---', 3);
+ if (secondDelimiter === -1) {
+ throw new ChangesetParseError('Changeset frontmatter must be closed with ---');
+ }
+
+ // Extract YAML and body
+ const yamlContent = trimmed.slice(3, secondDelimiter).trim();
+ const body = trimmed.slice(secondDelimiter + 3).trim();
+
+ // Parse YAML
+ let parsed: unknown;
+ try {
+ parsed = parseYaml(yamlContent);
+ } catch (yamlError) {
+ const message = yamlError instanceof Error ? yamlError.message : 'Invalid YAML';
+ throw new ChangesetParseError(`Invalid YAML in frontmatter: ${message}`);
+ }
+
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
+ throw new ChangesetParseError('Changeset frontmatter must contain a YAML object');
+ }
+
+ // Validate and extract bumps
+ const bumps: Record = {};
+
+ for (const [key, value] of Object.entries(parsed as Record)) {
+ if (!isValidBumpType(value)) {
+ throw new ChangesetParseError(
+ `Invalid bump type "${String(value)}" for contract "${key}". Must be ${VALID_BUMP_TYPES.join(', ')}.`
+ );
+ }
+ bumps[key] = value;
+ }
+
+ return { bumps, body };
+}
+
+/**
+ * Read all changeset files from a directory
+ *
+ * @param changesetsDir - Path to the changesets directory
+ * @returns Array of parsed changeset files
+ */
+export async function readChangesets(changesetsDir: string): Promise {
+ let files: string[];
+
+ try {
+ files = await readdir(changesetsDir);
+ } catch (error) {
+ // Directory doesn't exist or can't be read - no changesets
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
+ return [];
+ }
+ throw error;
+ }
+
+ // Filter to only .md files
+ const mdFiles = files.filter((file) => file.endsWith('.md'));
+
+ const changesets: ChangesetFile[] = [];
+
+ for (const filename of mdFiles) {
+ const filePath = join(changesetsDir, filename);
+ const content = await readFile(filePath, 'utf-8');
+
+ try {
+ const { bumps, body } = parseChangeset(content);
+ changesets.push({ filename, path: filePath, bumps, body });
+ } catch (error) {
+ // Re-throw with filename context
+ if (error instanceof ChangesetParseError) {
+ throw new ChangesetParseError(error.message, filename);
+ }
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ throw new ChangesetParseError(message, filename);
+ }
+ }
+
+ return changesets;
+}
diff --git a/packages/changesets/index.ts b/packages/changesets/index.ts
new file mode 100644
index 0000000..4be46a2
--- /dev/null
+++ b/packages/changesets/index.ts
@@ -0,0 +1,31 @@
+// Changesets
+export {
+ generateChangesetName,
+ generateUniqueChangesetName,
+} from './changesets/naming.js';
+export { createChangeset, type CreateChangesetResult } from './changesets/create.js';
+export {
+ parseChangeset,
+ readChangesets,
+ ChangesetParseError,
+ type ParsedChangesetContent,
+} from './changesets/read.js';
+export { aggregateBumps, extractContractChanges } from './changesets/consume.js';
+
+// Versioning
+export {
+ VersionManager,
+ PreReleaseManager,
+ VERSIONS_FILE,
+ SNAPSHOTS_DIR,
+ CHANGESETS_DIR,
+ PRE_RELEASE_FILE,
+ DEFAULT_VERSION,
+ SPEC_EXTENSIONS,
+ incrementVersion,
+ incrementVersionWithPreRelease,
+ VersionError,
+ type BumpOperationResult,
+} from './versioning/manager.js';
+export { formatDate, appendChangelog } from './versioning/changelog.js';
+export { updateSpecVersion } from './versioning/spec-updater.js';
diff --git a/packages/changesets/package.json b/packages/changesets/package.json
new file mode 100644
index 0000000..57f40ef
--- /dev/null
+++ b/packages/changesets/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@contractual/changesets",
+ "private": false,
+ "version": "0.1.0-dev.5",
+ "description": "Changeset creation, parsing, and versioning utilities for Contractual",
+ "license": "MIT",
+ "type": "module",
+ "main": "./dist/index.js",
+ "module": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ },
+ "./changesets": {
+ "types": "./dist/changesets/index.d.ts",
+ "import": "./dist/changesets/index.js"
+ },
+ "./versioning": {
+ "types": "./dist/versioning/index.d.ts",
+ "import": "./dist/versioning/index.js"
+ }
+ },
+ "sideEffects": false,
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/changesets"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "pnpm rimraf dist",
+ "build": "tsc -p tsconfig.build.json"
+ },
+ "files": [
+ "dist"
+ ],
+ "dependencies": {
+ "@contractual/types": "workspace:*",
+ "semver": "^7.7.1",
+ "yaml": "^2.7.0"
+ },
+ "devDependencies": {
+ "@types/semver": "^7.5.8"
+ },
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/changesets/tsconfig.build.json b/packages/changesets/tsconfig.build.json
new file mode 100644
index 0000000..46b1b04
--- /dev/null
+++ b/packages/changesets/tsconfig.build.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "composite": true,
+ "incremental": true
+ },
+ "references": [
+ { "path": "../types/tsconfig.build.json" }
+ ]
+}
diff --git a/packages/changesets/tsconfig.json b/packages/changesets/tsconfig.json
new file mode 100644
index 0000000..c256fc3
--- /dev/null
+++ b/packages/changesets/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "./dist",
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "exactOptionalPropertyTypes": false,
+ "noFallthroughCasesInSwitch": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["**/*.ts"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/packages/changesets/versioning/changelog.ts b/packages/changesets/versioning/changelog.ts
new file mode 100644
index 0000000..bdb7be6
--- /dev/null
+++ b/packages/changesets/versioning/changelog.ts
@@ -0,0 +1,74 @@
+import { existsSync, readFileSync, writeFileSync } from 'node:fs';
+import type { BumpResult } from '@contractual/types';
+
+/**
+ * Format a date as YYYY-MM-DD
+ * @param date - The date to format
+ * @returns The formatted date string
+ */
+export function formatDate(date: Date): string {
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0');
+ const day = String(date.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+}
+
+/**
+ * Format a single bump result as a changelog entry
+ */
+function formatBumpEntry(bump: BumpResult, date: Date): string {
+ const dateStr = formatDate(date);
+ const header = `## [${bump.contract}] v${bump.newVersion} - ${dateStr}`;
+ const changes = bump.changes.trim();
+
+ return `${header}\n\n${changes}`;
+}
+
+/**
+ * Append version bump entries to CHANGELOG.md
+ * Creates the file if it doesn't exist.
+ * Inserts entries after the "# Changelog" heading, or at the top if no heading.
+ * @param changelogPath - Path to the CHANGELOG.md file
+ * @param bumps - Array of bump results to append
+ */
+export function appendChangelog(changelogPath: string, bumps: BumpResult[]): void {
+ if (bumps.length === 0) {
+ return;
+ }
+
+ const date = new Date();
+ const newEntries = bumps
+ .map((bump) => formatBumpEntry(bump, date))
+ .join('\n\n');
+
+ if (!existsSync(changelogPath)) {
+ // Create new changelog with header and entries
+ const content = `# Changelog\n\n${newEntries}\n`;
+ writeFileSync(changelogPath, content, 'utf-8');
+ return;
+ }
+
+ const existingContent = readFileSync(changelogPath, 'utf-8');
+ const changelogHeading = '# Changelog';
+ const headingIndex = existingContent.indexOf(changelogHeading);
+
+ let newContent: string;
+
+ if (headingIndex !== -1) {
+ // Insert after the heading line
+ const afterHeading = headingIndex + changelogHeading.length;
+ const beforeHeading = existingContent.slice(0, afterHeading);
+ const afterContent = existingContent.slice(afterHeading);
+
+ // Preserve any blank lines after heading, then insert entries
+ const leadingWhitespaceMatch = afterContent.match(/^(\r?\n)*/);
+ const leadingWhitespace = leadingWhitespaceMatch?.[0] ?? '\n\n';
+
+ newContent = `${beforeHeading}\n\n${newEntries}${leadingWhitespace.length > 2 ? leadingWhitespace : '\n\n'}${afterContent.trimStart()}`;
+ } else {
+ // No heading found, prepend entries with heading
+ newContent = `# Changelog\n\n${newEntries}\n\n${existingContent}`;
+ }
+
+ writeFileSync(changelogPath, newContent, 'utf-8');
+}
diff --git a/packages/changesets/versioning/index.ts b/packages/changesets/versioning/index.ts
new file mode 100644
index 0000000..d6f8d13
--- /dev/null
+++ b/packages/changesets/versioning/index.ts
@@ -0,0 +1,2 @@
+export * from './manager.js';
+export * from './changelog.js';
diff --git a/packages/changesets/versioning/manager.ts b/packages/changesets/versioning/manager.ts
new file mode 100644
index 0000000..9656d0c
--- /dev/null
+++ b/packages/changesets/versioning/manager.ts
@@ -0,0 +1,371 @@
+import { existsSync, readFileSync, writeFileSync, copyFileSync, unlinkSync } from 'node:fs';
+import { join, extname } from 'node:path';
+import * as semver from 'semver';
+import type { VersionsFile, SimpleVersionEntry, BumpType, PreReleaseState } from '@contractual/types';
+
+/**
+ * Default version for new contracts
+ */
+export const DEFAULT_VERSION = '0.0.0' as const;
+
+/**
+ * Supported spec file extensions for snapshot lookup
+ */
+export const SPEC_EXTENSIONS = ['.yaml', '.yml', '.json'] as const;
+
+/**
+ * Error thrown when version operations fail
+ */
+export class VersionError extends Error {
+ constructor(
+ message: string,
+ public readonly version?: string,
+ public readonly bumpType?: BumpType
+ ) {
+ super(message);
+ this.name = 'VersionError';
+ }
+}
+
+/**
+ * Result of a version bump operation
+ */
+export interface BumpOperationResult {
+ /** Version before the bump */
+ oldVersion: string;
+ /** Version after the bump */
+ newVersion: string;
+}
+
+/**
+ * Increment a version by a bump type
+ * @param version - The current version string (must be valid semver)
+ * @param bumpType - The type of version bump (major, minor, patch)
+ * @returns The new version string
+ * @throws {VersionError} If the version is invalid or increment fails
+ */
+export function incrementVersion(version: string, bumpType: BumpType): string {
+ if (!semver.valid(version)) {
+ throw new VersionError(`Invalid semver version: ${version}`, version, bumpType);
+ }
+ const newVersion = semver.inc(version, bumpType);
+ if (!newVersion) {
+ throw new VersionError(
+ `Failed to increment version ${version} with type ${bumpType}`,
+ version,
+ bumpType
+ );
+ }
+ return newVersion;
+}
+
+/**
+ * Filename for the versions registry
+ */
+export const VERSIONS_FILE = 'versions.json' as const;
+
+/**
+ * Directory name for snapshots
+ */
+export const SNAPSHOTS_DIR = 'snapshots' as const;
+
+/**
+ * Directory name for changesets
+ */
+export const CHANGESETS_DIR = 'changesets' as const;
+
+/**
+ * Filename for pre-release state
+ */
+export const PRE_RELEASE_FILE = 'pre.json' as const;
+
+/**
+ * Manages contract versions and snapshots
+ */
+export class VersionManager {
+ private readonly versionsPath: string;
+ private readonly snapshotsDir: string;
+ private versions: VersionsFile;
+
+ constructor(contractualDir: string) {
+ this.versionsPath = join(contractualDir, VERSIONS_FILE);
+ this.snapshotsDir = join(contractualDir, SNAPSHOTS_DIR);
+ this.versions = this.load();
+ }
+
+ /**
+ * Load versions.json from disk
+ * @throws {VersionError} If the file exists but contains invalid JSON
+ */
+ private load(): VersionsFile {
+ if (!existsSync(this.versionsPath)) {
+ return {};
+ }
+
+ const content = readFileSync(this.versionsPath, 'utf-8');
+ try {
+ const parsed: unknown = JSON.parse(content);
+ if (!this.isValidVersionsFile(parsed)) {
+ throw new VersionError(`Invalid versions.json format at ${this.versionsPath}`);
+ }
+ return parsed;
+ } catch (error) {
+ if (error instanceof VersionError) {
+ throw error;
+ }
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ throw new VersionError(`Failed to parse versions.json: ${message}`);
+ }
+ }
+
+ /**
+ * Type guard to validate VersionsFile structure
+ */
+ private isValidVersionsFile(value: unknown): value is VersionsFile {
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
+ return false;
+ }
+ for (const entry of Object.values(value as Record)) {
+ if (!this.isValidVersionEntry(entry)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Type guard to validate SimpleVersionEntry structure
+ */
+ private isValidVersionEntry(value: unknown): value is SimpleVersionEntry {
+ if (typeof value !== 'object' || value === null) {
+ return false;
+ }
+ const entry = value as Record;
+ return typeof entry.version === 'string' && typeof entry.released === 'string';
+ }
+
+ /**
+ * Get current version for a contract
+ * @param contractName - The contract name to look up
+ * @returns The version string, or null if not found
+ */
+ getVersion(contractName: string): string | null {
+ const entry = this.versions[contractName];
+ return entry?.version ?? null;
+ }
+
+ /**
+ * Get snapshot path for a contract
+ * @param contractName - The contract name to look up
+ * @returns The snapshot file path, or null if not found
+ */
+ getSnapshotPath(contractName: string): string | null {
+ for (const ext of SPEC_EXTENSIONS) {
+ const snapshotPath = join(this.snapshotsDir, `${contractName}${ext}`);
+ if (existsSync(snapshotPath)) {
+ return snapshotPath;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Bump version, update versions.json, and copy spec to snapshots
+ * @param contractName - The contract name to bump
+ * @param bumpType - The type of version bump (major, minor, patch)
+ * @param specPath - Path to the current spec file to snapshot
+ * @returns The old and new version strings
+ * @throws {VersionError} If the bump operation fails
+ */
+ bump(contractName: string, bumpType: BumpType, specPath: string): BumpOperationResult {
+ const currentEntry = this.versions[contractName];
+ const oldVersion = currentEntry?.version ?? DEFAULT_VERSION;
+
+ // Use the shared incrementVersion function for consistent error handling
+ const newVersion = incrementVersion(oldVersion, bumpType);
+
+ // Update versions entry
+ this.versions[contractName] = {
+ version: newVersion,
+ released: new Date().toISOString(),
+ };
+
+ // Copy spec to snapshots directory
+ const ext = extname(specPath) || '.yaml';
+ const snapshotPath = join(this.snapshotsDir, `${contractName}${ext}`);
+ copyFileSync(specPath, snapshotPath);
+
+ // Save versions.json
+ this.save();
+
+ return { oldVersion, newVersion };
+ }
+
+ /**
+ * Set version for a contract (used for initial version setup)
+ * @param contractName - The contract name
+ * @param version - The version to set
+ * @param specPath - Path to the spec file to snapshot
+ */
+ setVersion(contractName: string, version: string, specPath: string): void {
+ if (!semver.valid(version)) {
+ throw new VersionError(`Invalid semver version: ${version}`, version);
+ }
+
+ // Update versions entry
+ this.versions[contractName] = {
+ version,
+ released: new Date().toISOString(),
+ };
+
+ // Copy spec to snapshots directory
+ const ext = extname(specPath) || '.yaml';
+ const snapshotPath = join(this.snapshotsDir, `${contractName}${ext}`);
+ copyFileSync(specPath, snapshotPath);
+
+ // Save versions.json
+ this.save();
+ }
+
+ /**
+ * Save versions.json to disk
+ */
+ private save(): void {
+ const content = JSON.stringify(this.versions, null, 2);
+ writeFileSync(this.versionsPath, content, 'utf-8');
+ }
+
+ /**
+ * Get all contract versions
+ * @returns Map of contract names to versions
+ */
+ getAllVersions(): Record {
+ const result: Record = {};
+ for (const [name, entry] of Object.entries(this.versions)) {
+ result[name] = entry.version;
+ }
+ return result;
+ }
+}
+
+/**
+ * Manages pre-release state
+ */
+export class PreReleaseManager {
+ private readonly prePath: string;
+
+ constructor(contractualDir: string) {
+ this.prePath = join(contractualDir, PRE_RELEASE_FILE);
+ }
+
+ /**
+ * Check if pre-release mode is active
+ */
+ isActive(): boolean {
+ return existsSync(this.prePath);
+ }
+
+ /**
+ * Get current pre-release state
+ * @returns The pre-release state, or null if not in pre-release mode
+ */
+ getState(): PreReleaseState | null {
+ if (!this.isActive()) {
+ return null;
+ }
+
+ try {
+ const content = readFileSync(this.prePath, 'utf-8');
+ return JSON.parse(content) as PreReleaseState;
+ } catch {
+ return null;
+ }
+ }
+
+ /**
+ * Enter pre-release mode
+ * @param tag - The pre-release tag (e.g., "alpha", "beta", "rc")
+ * @param versionManager - VersionManager to get current versions
+ */
+ enter(tag: string, versionManager: VersionManager): void {
+ if (this.isActive()) {
+ throw new VersionError(`Already in pre-release mode. Run 'pre exit' first.`);
+ }
+
+ // Validate tag
+ if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(tag)) {
+ throw new VersionError(
+ `Invalid pre-release tag: ${tag}. Must start with letter, contain only letters, numbers, and hyphens.`
+ );
+ }
+
+ const state: PreReleaseState = {
+ tag,
+ enteredAt: new Date().toISOString(),
+ initialVersions: versionManager.getAllVersions(),
+ };
+
+ writeFileSync(this.prePath, JSON.stringify(state, null, 2), 'utf-8');
+ }
+
+ /**
+ * Exit pre-release mode
+ */
+ exit(): void {
+ if (!this.isActive()) {
+ throw new VersionError('Not in pre-release mode.');
+ }
+
+ unlinkSync(this.prePath);
+ }
+
+ /**
+ * Get the pre-release tag
+ * @returns The tag, or null if not in pre-release mode
+ */
+ getTag(): string | null {
+ const state = this.getState();
+ return state?.tag ?? null;
+ }
+}
+
+/**
+ * Increment a version with pre-release support
+ * @param version - The current version string
+ * @param bumpType - The type of version bump
+ * @param preReleaseTag - Optional pre-release tag (e.g., "beta")
+ * @returns The new version string
+ */
+export function incrementVersionWithPreRelease(
+ version: string,
+ bumpType: BumpType,
+ preReleaseTag?: string
+): string {
+ if (!semver.valid(version)) {
+ throw new VersionError(`Invalid semver version: ${version}`, version, bumpType);
+ }
+
+ const parsed = semver.parse(version);
+ if (!parsed) {
+ throw new VersionError(`Failed to parse version: ${version}`, version, bumpType);
+ }
+
+ // If no pre-release tag, use normal increment
+ if (!preReleaseTag) {
+ return incrementVersion(version, bumpType);
+ }
+
+ // If already a pre-release with the same tag, just bump the pre-release number
+ if (parsed.prerelease.length > 0 && parsed.prerelease[0] === preReleaseTag) {
+ const newVersion = semver.inc(version, 'prerelease', preReleaseTag);
+ if (!newVersion) {
+ throw new VersionError(`Failed to increment pre-release version`, version, bumpType);
+ }
+ return newVersion;
+ }
+
+ // Otherwise, apply the bump type and start a new pre-release
+ const baseVersion = incrementVersion(version, bumpType);
+ return `${baseVersion}-${preReleaseTag}.0`;
+}
diff --git a/packages/changesets/versioning/spec-updater.ts b/packages/changesets/versioning/spec-updater.ts
new file mode 100644
index 0000000..c9b8653
--- /dev/null
+++ b/packages/changesets/versioning/spec-updater.ts
@@ -0,0 +1,110 @@
+/**
+ * Spec Version Updater
+ *
+ * Updates the version field inside a spec file (e.g., info.version in OpenAPI)
+ * to keep the spec's internal version in sync with the tracked version.
+ */
+
+import { readFileSync, writeFileSync } from 'node:fs';
+import { extname } from 'node:path';
+import { parseDocument } from 'yaml';
+import type { ContractType } from '@contractual/types';
+
+/**
+ * Contract types that have a version field in the spec
+ */
+const VERSION_FIELD_PATHS: Partial> = {
+ openapi: ['info', 'version'],
+ asyncapi: ['info', 'version'],
+ odcs: ['version'],
+};
+
+/**
+ * Detect indentation used in a JSON file
+ */
+function detectJsonIndent(content: string): number {
+ const match = content.match(/^(\s+)"/m);
+ return match?.[1]?.length ?? 2;
+}
+
+/**
+ * Ensure nested path exists in a plain object, creating intermediate objects as needed.
+ * Returns the parent object of the last key.
+ */
+function ensureJsonPath(
+ root: Record,
+ fieldPath: readonly string[]
+): Record {
+ let current = root;
+ for (let i = 0; i < fieldPath.length - 1; i++) {
+ const key = fieldPath[i]!;
+ if (typeof current[key] !== 'object' || current[key] === null) {
+ current[key] = {};
+ }
+ current = current[key] as Record;
+ }
+ return current;
+}
+
+/**
+ * Update the version field inside a JSON spec file.
+ * Creates missing intermediate objects if needed.
+ */
+function updateJsonSpec(specPath: string, fieldPath: readonly string[], newVersion: string): void {
+ const content = readFileSync(specPath, 'utf-8');
+ const spec = JSON.parse(content) as Record;
+
+ const parent = ensureJsonPath(spec, fieldPath);
+ parent[fieldPath.at(-1)!] = newVersion;
+
+ const indent = detectJsonIndent(content);
+ const trailingNewline = content.endsWith('\n') ? '\n' : '';
+ writeFileSync(specPath, JSON.stringify(spec, null, indent) + trailingNewline, 'utf-8');
+}
+
+/**
+ * Update the version field inside a YAML spec file.
+ * Uses parseDocument() to preserve comments, formatting, and key ordering.
+ * Creates missing intermediate keys if needed.
+ */
+function updateYamlSpec(specPath: string, fieldPath: readonly string[], newVersion: string): void {
+ const content = readFileSync(specPath, 'utf-8');
+ const doc = parseDocument(content);
+
+ // setIn creates intermediate nodes automatically
+ doc.setIn([...fieldPath], newVersion);
+
+ writeFileSync(specPath, doc.toString(), 'utf-8');
+}
+
+/**
+ * Update the version field inside a spec file.
+ *
+ * Reads the spec, updates the appropriate version field based on contract type,
+ * and writes it back preserving the original format (YAML comments, JSON indentation).
+ * If the version field (or its parent, e.g. `info`) is missing, it will be created.
+ *
+ * @param specPath - Absolute path to the spec file
+ * @param newVersion - The new version string to set
+ * @param contractType - The type of contract (openapi, asyncapi, odcs, json-schema)
+ * @returns true if the file was updated, false if the spec type has no version field (e.g. json-schema)
+ */
+export function updateSpecVersion(
+ specPath: string,
+ newVersion: string,
+ contractType: ContractType
+): boolean {
+ const fieldPath = VERSION_FIELD_PATHS[contractType];
+ if (!fieldPath) {
+ return false;
+ }
+
+ const ext = extname(specPath).toLowerCase();
+ if (ext === '.json') {
+ updateJsonSpec(specPath, fieldPath, newVersion);
+ } else {
+ updateYamlSpec(specPath, fieldPath, newVersion);
+ }
+
+ return true;
+}
diff --git a/packages/cli/bin/cli.js b/packages/cli/bin/cli.js
index 924fff1..6021ca3 100755
--- a/packages/cli/bin/cli.js
+++ b/packages/cli/bin/cli.js
@@ -1,2 +1,2 @@
#!/usr/bin/env node
-import '../dist/index.js';
+import '../dist/commands.js';
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 38f1cf3..1852b64 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,12 +1,20 @@
{
"name": "@contractual/cli",
"private": false,
- "version": "0.0.0",
+ "version": "0.1.0-dev.5",
"license": "MIT",
"type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
"bin": {
"contractual": "./bin/cli.js"
},
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ }
+ },
"repository": {
"type": "git",
"url": "https://github.com/contractual-dev/contractual.git",
@@ -33,7 +41,7 @@
}
],
"engines": {
- "node": ">=18.12.0"
+ "node": ">=20.0.0"
},
"scripts": {
"prebuild": "pnpm rimraf dist",
@@ -45,23 +53,28 @@
"files": [
"bin",
"dist",
+ "src/config/schema.json",
"README.md"
],
"dependencies": {
- "@contractual/generators.contract": "workspace:*",
- "@contractual/generators.diff": "workspace:*",
- "@contractual/generators.spec": "workspace:*",
+ "@contractual/changesets": "workspace:*",
+ "@contractual/governance": "workspace:*",
+ "@contractual/types": "workspace:*",
+ "@inquirer/prompts": "^8.1.0",
+ "ajv": "^8.17.1",
+ "ajv-formats": "^3.0.1",
"chalk": "^5.4.1",
"commander": "^12.1.0",
- "inquirer": "^12.3.2",
- "ora": "^8.1.1"
+ "fast-glob": "^3.3.3",
+ "ora": "^8.1.1",
+ "yaml": "^2.7.0"
},
"publishConfig": {
"access": "public",
"provenance": true
},
"devDependencies": {
- "@vitest/coverage-c8": "^0.33.0",
+ "@vitest/coverage-v8": "^3.0.0",
"vitest": "^3.0.3"
}
}
diff --git a/packages/cli/src/commands.ts b/packages/cli/src/commands.ts
index 1bff637..cd3a3d6 100644
--- a/packages/cli/src/commands.ts
+++ b/packages/cli/src/commands.ts
@@ -1,22 +1,102 @@
import { Command } from 'commander';
-import { graduateSpec, generateContract } from './commands/generate.command.js';
+import { initCommand } from './commands/init.command.js';
+import { contractAddCommand, contractListCommand } from './commands/contract.command.js';
+import { lintCommand } from './commands/lint.command.js';
+import { diffCommand } from './commands/diff.command.js';
+import { breakingCommand } from './commands/breaking.command.js';
+import { changesetCommand } from './commands/changeset.command.js';
+import { versionCommand } from './commands/version.command.js';
+import { preEnterCommand, preExitCommand, preStatusCommand } from './commands/pre.command.js';
+import { statusCommand } from './commands/status.command.js';
const program = new Command();
-program.name('contractual');
-
-const generateContractCommand = new Command('generate')
- .description('Generate resources')
- .command('contract')
- .description('Generate a contract based on the provided OpenAPI file')
- .action(() => {
- return generateContract();
- });
-
-const graduateSpecCommand = new Command('graduate').command('spec').action(() => {
- return graduateSpec();
-});
-program.addCommand(graduateSpecCommand);
-program.addCommand(generateContractCommand);
+program.name('contractual').description('Schema contract lifecycle orchestrator').version('0.1.0');
+
+program
+ .command('init')
+ .description('Initialize Contractual in this repository')
+ .option('-V, --initial-version ', 'Initial version for contracts')
+ .option('--versioning ', 'Versioning mode: independent, fixed')
+ .option('-y, --yes', 'Skip prompts and use defaults')
+ .option('--force', 'Reinitialize existing project')
+ .action(initCommand);
+
+const contractCmd = program.command('contract').description('Manage contracts');
+
+contractCmd
+ .command('add')
+ .description('Add a new contract to the configuration')
+ .option('-n, --name ', 'Contract name')
+ .option('-t, --type ', 'Contract type: openapi, asyncapi, json-schema, odcs')
+ .option('-p, --path ', 'Path to spec file')
+ .option('--initial-version ', 'Initial version (default: 0.0.0)')
+ .option('--skip-validation', 'Skip spec validation')
+ .option('-y, --yes', 'Skip prompts and use defaults')
+ .action(contractAddCommand);
+
+contractCmd
+ .command('list [name]')
+ .description('List contracts (optionally filter by name)')
+ .option('--json', 'Output as JSON')
+ .action(contractListCommand);
+
+program
+ .command('lint')
+ .description('Lint all configured contracts')
+ .option('-c, --contract ', 'Lint specific contract')
+ .option('--format ', 'Output format: text, json', 'text')
+ .option('--fail-on-warn', 'Exit 1 on warnings')
+ .action(lintCommand);
+
+program
+ .command('diff')
+ .description('Show all changes between current specs and last versioned snapshots')
+ .option('-c, --contract ', 'Diff specific contract')
+ .option('--format ', 'Output format: text, json', 'text')
+ .option('--severity ', 'Filter: all, breaking, non-breaking, patch', 'all')
+ .option('--verbose', 'Show JSON Pointer paths for each change')
+ .action(diffCommand);
+
+program
+ .command('breaking')
+ .description('Detect breaking changes against last snapshot')
+ .option('-c, --contract ', 'Check specific contract')
+ .option('--format ', 'Output format: text, json', 'text')
+ .option('--fail-on ', 'Exit 1 on: breaking, non-breaking, any', 'breaking')
+ .action(breakingCommand);
-program.parse(process.argv);
+program
+ .command('changeset')
+ .description('Create changeset from detected changes')
+ .action(changesetCommand);
+
+program
+ .command('version')
+ .description('Consume changesets and bump versions')
+ .option('-y, --yes', 'Skip confirmation prompt')
+ .option('--dry-run', 'Preview without applying')
+ .option('--json', 'Output JSON (implies --yes)')
+ .option('--no-sync-version', 'Skip updating version field inside spec files')
+ .action(versionCommand);
+
+const preCmd = program.command('pre').description('Manage pre-release versions');
+
+preCmd
+ .command('enter ')
+ .description('Enter pre-release mode (e.g., alpha, beta, rc)')
+ .action(preEnterCommand);
+
+preCmd.command('exit').description('Exit pre-release mode').action(preExitCommand);
+
+preCmd.command('status').description('Show pre-release status').action(preStatusCommand);
+
+program
+ .command('status')
+ .description('Show current versions and pending changesets')
+ .action(statusCommand);
+
+program.parseAsync(process.argv).catch((err) => {
+ console.error(`Error: ${err.message}`);
+ process.exit(2);
+});
diff --git a/packages/cli/src/commands/breaking.command.ts b/packages/cli/src/commands/breaking.command.ts
new file mode 100644
index 0000000..596e844
--- /dev/null
+++ b/packages/cli/src/commands/breaking.command.ts
@@ -0,0 +1,166 @@
+/**
+ * Breaking Command
+ *
+ * Detect breaking changes against snapshots.
+ * This is a CI gate β exits 1 if breaking changes are found.
+ *
+ * Uses the shared diffContracts() function internally.
+ */
+
+import chalk from 'chalk';
+import ora from 'ora';
+import { loadConfig } from '../config/index.js';
+import { diffContracts } from '../core/diff.js';
+import { formatSeverity } from '../utils/output.js';
+import type { DiffResult } from '@contractual/types';
+
+interface BreakingOptions {
+ contract?: string;
+ format?: 'text' | 'json';
+ failOn?: 'breaking' | 'non-breaking' | 'any';
+}
+
+interface BreakingCommandResult {
+ hasBreaking: boolean;
+ results: DiffResult[];
+}
+
+/**
+ * Detect breaking changes against snapshots
+ */
+export async function breakingCommand(options: BreakingOptions): Promise {
+ const spinner = ora('Loading configuration...').start();
+
+ let config;
+ try {
+ config = loadConfig();
+ spinner.succeed('Configuration loaded');
+ } catch (error) {
+ spinner.fail('Failed to load configuration');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red(message));
+ process.exitCode = 1;
+ return;
+ }
+
+ const checkSpinner = ora('Checking for breaking changes...').start();
+
+ try {
+ const { results } = await diffContracts(config, {
+ contracts: options.contract ? [options.contract] : undefined,
+ includeEmpty: true,
+ });
+
+ const hasBreaking = results.some((r) => r.summary.breaking > 0);
+
+ if (hasBreaking) {
+ checkSpinner.fail('Breaking changes detected');
+ } else {
+ checkSpinner.succeed('No breaking changes');
+ }
+
+ // Output results
+ console.log();
+ if (options.format === 'json') {
+ const output: BreakingCommandResult = { hasBreaking, results };
+ console.log(JSON.stringify(output, null, 2));
+ } else {
+ printTextResults(results);
+ }
+
+ // Determine exit code based on --fail-on option
+ const failOn = options.failOn ?? 'breaking';
+ let shouldFail = false;
+
+ if (failOn === 'any') {
+ // Fail on any detected changes
+ shouldFail = results.some((r) => r.changes.length > 0);
+ } else if (failOn === 'non-breaking') {
+ // Fail on non-breaking or breaking changes
+ shouldFail = results.some((r) => r.summary.breaking > 0 || r.summary.nonBreaking > 0);
+ } else {
+ // Default: fail only on breaking changes
+ shouldFail = hasBreaking;
+ }
+
+ if (shouldFail) {
+ process.exitCode = 1;
+ }
+ } catch (error) {
+ checkSpinner.fail('Failed to check for breaking changes');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Error:'), message);
+ process.exitCode = 1;
+ }
+}
+
+/**
+ * Print results in human-readable text format
+ */
+function printTextResults(results: DiffResult[]): void {
+ if (results.length === 0) {
+ console.log(chalk.gray('No contracts were checked.'));
+ return;
+ }
+
+ for (const result of results) {
+ console.log(chalk.bold.underline(result.contract));
+ console.log();
+
+ if (result.changes.length === 0) {
+ console.log(chalk.gray(' No changes detected.'));
+ console.log();
+ continue;
+ }
+
+ // Group changes by severity
+ const breaking = result.changes.filter((c) => c.severity === 'breaking');
+ const nonBreaking = result.changes.filter((c) => c.severity === 'non-breaking');
+ const patch = result.changes.filter((c) => c.severity === 'patch');
+ const unknown = result.changes.filter((c) => c.severity === 'unknown');
+
+ // Print summary
+ console.log(
+ ` Summary: ` +
+ `${chalk.red(String(result.summary.breaking))} breaking, ` +
+ `${chalk.yellow(String(result.summary.nonBreaking))} non-breaking, ` +
+ `${chalk.green(String(result.summary.patch))} patch, ` +
+ `${chalk.gray(String(result.summary.unknown))} unknown`
+ );
+ console.log(` Suggested bump: ${chalk.cyan(result.suggestedBump)}`);
+ console.log();
+
+ // Print changes by severity
+ if (breaking.length > 0) {
+ console.log(` ${formatSeverity('breaking')} Changes:`);
+ for (const change of breaking) {
+ console.log(` - ${change.path}: ${change.message}`);
+ }
+ console.log();
+ }
+
+ if (nonBreaking.length > 0) {
+ console.log(` ${formatSeverity('non-breaking')} Changes:`);
+ for (const change of nonBreaking) {
+ console.log(` - ${change.path}: ${change.message}`);
+ }
+ console.log();
+ }
+
+ if (patch.length > 0) {
+ console.log(` ${formatSeverity('patch')} Changes:`);
+ for (const change of patch) {
+ console.log(` - ${change.path}: ${change.message}`);
+ }
+ console.log();
+ }
+
+ if (unknown.length > 0) {
+ console.log(` ${formatSeverity('unknown')} Changes:`);
+ for (const change of unknown) {
+ console.log(` - ${change.path}: ${change.message}`);
+ }
+ console.log();
+ }
+ }
+}
diff --git a/packages/cli/src/commands/changeset.command.ts b/packages/cli/src/commands/changeset.command.ts
new file mode 100644
index 0000000..ba6a733
--- /dev/null
+++ b/packages/cli/src/commands/changeset.command.ts
@@ -0,0 +1,79 @@
+/**
+ * Changeset Command
+ *
+ * Auto-generate changeset from detected changes.
+ * Uses the shared diffContracts() function internally.
+ */
+
+import { writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import chalk from 'chalk';
+import ora from 'ora';
+import { loadConfig } from '../config/index.js';
+import { diffContracts } from '../core/diff.js';
+import { CHANGESETS_DIR } from '../utils/files.js';
+import {
+ createChangeset,
+ generateUniqueChangesetName,
+ readChangesets,
+} from '@contractual/changesets';
+
+/**
+ * Auto-generate changeset from detected changes
+ */
+export async function changesetCommand(): Promise {
+ const spinner = ora('Loading configuration...').start();
+
+ let config;
+ try {
+ config = loadConfig();
+ spinner.succeed('Configuration loaded');
+ } catch (error) {
+ spinner.fail('Failed to load configuration');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red(message));
+ process.exit(1);
+ }
+
+ // Detect changes for all contracts using shared diff logic
+ const diffSpinner = ora('Detecting changes...').start();
+
+ try {
+ const { results: diffResults, contractualDir } = await diffContracts(config, {
+ includeEmpty: false, // Only get contracts with actual changes
+ });
+
+ if (diffResults.length === 0) {
+ diffSpinner.succeed('No changes detected');
+ console.log(chalk.gray('No changeset created.'));
+ process.exit(0);
+ }
+
+ diffSpinner.succeed(`Detected changes in ${diffResults.length} contract(s)`);
+
+ // Create changeset content
+ const { content: changesetContent } = createChangeset(diffResults);
+
+ // Read existing changesets to ensure unique name
+ const changesetsDir = join(contractualDir, CHANGESETS_DIR);
+ const existingChangesets = await readChangesets(changesetsDir);
+ const existingNames = existingChangesets.map((c) => c.filename.replace(/\.md$/, ''));
+ const changesetName = generateUniqueChangesetName(existingNames);
+
+ // Write changeset file
+ const changesetPath = join(changesetsDir, `${changesetName}.md`);
+
+ writeFileSync(changesetPath, changesetContent, 'utf-8');
+
+ console.log();
+ console.log(chalk.green('Created changeset:'), chalk.cyan(changesetPath));
+ console.log();
+ console.log(chalk.gray('You can edit this file to add more details about the changes.'));
+ console.log(chalk.gray('Run `contractual version` to consume changesets and bump versions.'));
+ } catch (error) {
+ diffSpinner.fail('Failed to detect changes');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Error:'), message);
+ process.exit(1);
+ }
+}
diff --git a/packages/cli/src/commands/contract.command.ts b/packages/cli/src/commands/contract.command.ts
new file mode 100644
index 0000000..c62b9a9
--- /dev/null
+++ b/packages/cli/src/commands/contract.command.ts
@@ -0,0 +1,374 @@
+import { existsSync, readFileSync, writeFileSync } from 'node:fs';
+import { join, resolve, extname } from 'node:path';
+import chalk from 'chalk';
+import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
+import { VersionManager, updateSpecVersion } from '@contractual/changesets';
+import { loadConfig } from '../config/index.js';
+import {
+ ensureContractualDir,
+ detectSpecType,
+ CONTRACTUAL_DIR,
+ findContractualDir,
+} from '../utils/files.js';
+import {
+ promptInput,
+ promptSelect,
+ promptVersion,
+ CONTRACT_TYPE_CHOICES,
+ type PromptOptions,
+} from '../utils/prompts.js';
+import type { ContractDefinition, ContractType } from '@contractual/types';
+
+/**
+ * Default version for new contracts
+ */
+const DEFAULT_VERSION = '0.0.0';
+
+/**
+ * Options for the contract add command
+ */
+interface ContractAddOptions extends PromptOptions {
+ /** Contract name */
+ name?: string;
+ /** Contract type */
+ type?: ContractType;
+ /** Path to spec file */
+ path?: string;
+ /** Initial version */
+ initialVersion?: string;
+ /** Skip validation */
+ skipValidation?: boolean;
+}
+
+/**
+ * Add a new contract to the configuration
+ */
+export async function contractAddCommand(options: ContractAddOptions = {}): Promise {
+ const cwd = process.cwd();
+ const configPath = join(cwd, 'contractual.yaml');
+
+ // Check if initialized
+ if (!existsSync(configPath)) {
+ console.log(chalk.red('Not initialized:') + ' contractual.yaml not found');
+ console.log(chalk.dim('Run `contractual init` first'));
+ process.exitCode = 1;
+ return;
+ }
+
+ // Read existing config
+ const configContent = readFileSync(configPath, 'utf-8');
+ const config = parseYaml(configContent) as {
+ contracts?: ContractDefinition[];
+ changeset?: unknown;
+ versioning?: unknown;
+ ai?: unknown;
+ };
+
+ if (!config.contracts) {
+ config.contracts = [];
+ }
+
+ // Get contract details through prompts or options
+ const contractName = await getContractName(config.contracts, options);
+ if (!contractName) return;
+
+ const specPath = await getSpecPath(cwd, options);
+ if (!specPath) return;
+
+ const contractType = await getContractType(cwd, specPath, options);
+ if (!contractType) return;
+
+ const version = await getVersion(options);
+
+ // Validate spec file
+ if (!options.skipValidation) {
+ const absolutePath = resolve(cwd, specPath);
+ const detectedType = detectSpecType(absolutePath);
+
+ if (!detectedType) {
+ console.log(chalk.red('Invalid spec file:') + ' Could not detect spec type');
+ console.log(chalk.dim(`Expected: ${contractType}`));
+ process.exitCode = 1;
+ return;
+ }
+
+ if (detectedType !== contractType) {
+ console.log(
+ chalk.yellow('Type mismatch:') +
+ ` Detected ${chalk.cyan(detectedType)}, specified ${chalk.cyan(contractType)}`
+ );
+ console.log(chalk.dim('Use --skip-validation to override'));
+ process.exitCode = 1;
+ return;
+ }
+
+ console.log(chalk.green('β') + ` Valid ${contractType} spec`);
+ }
+
+ // Create contract definition
+ const contract: ContractDefinition = {
+ name: contractName,
+ type: contractType,
+ path: specPath,
+ };
+
+ // Add to config
+ config.contracts.push(contract);
+
+ // Write updated config
+ const yamlContent = stringifyYaml(config, {
+ lineWidth: 100,
+ singleQuote: true,
+ });
+ writeFileSync(configPath, yamlContent, 'utf-8');
+
+ // Ensure .contractual directory exists and create snapshot
+ const contractualDir = findContractualDir(cwd) ?? join(cwd, CONTRACTUAL_DIR);
+ ensureContractualDir(cwd);
+
+ const versionManager = new VersionManager(contractualDir);
+ const absolutePath = resolve(cwd, specPath);
+ updateSpecVersion(absolutePath, version, contractType);
+ versionManager.setVersion(contractName, version, absolutePath);
+
+ // Print summary
+ const snapshotExt = extname(specPath) || '.yaml';
+ console.log();
+ console.log(
+ chalk.green('β') + ` Added ${chalk.cyan(contractName)} (${contractType}) at v${version}`
+ );
+ console.log();
+ console.log(chalk.bold('Updated:'));
+ console.log(` ${chalk.yellow('~')} contractual.yaml`);
+ console.log(chalk.bold('Created:'));
+ console.log(` ${chalk.green('+')} .contractual/snapshots/${contractName}${snapshotExt}`);
+ console.log(` ${chalk.green('+')} .contractual/versions.json (updated)`);
+}
+
+/**
+ * Get contract name through prompts or options
+ */
+async function getContractName(
+ existingContracts: ContractDefinition[],
+ options: ContractAddOptions
+): Promise {
+ const existingNames = new Set(existingContracts.map((c) => c.name));
+
+ if (options.name) {
+ if (existingNames.has(options.name)) {
+ console.log(chalk.red('Contract exists:') + ` ${options.name} already defined`);
+ process.exitCode = 1;
+ return null;
+ }
+ return options.name;
+ }
+
+ const name = await promptInput('Contract name:', '', options);
+
+ if (!name) {
+ console.log(chalk.red('Contract name is required'));
+ process.exitCode = 1;
+ return null;
+ }
+
+ if (existingNames.has(name)) {
+ console.log(chalk.red('Contract exists:') + ` ${name} already defined`);
+ process.exitCode = 1;
+ return null;
+ }
+
+ // Validate name format (alphanumeric, hyphens, underscores)
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
+ console.log(
+ chalk.red('Invalid name:') +
+ ' Must start with letter, contain only letters, numbers, hyphens, underscores'
+ );
+ process.exitCode = 1;
+ return null;
+ }
+
+ return name;
+}
+
+/**
+ * Get spec path through prompts or options
+ */
+async function getSpecPath(cwd: string, options: ContractAddOptions): Promise {
+ if (options.path) {
+ const absolutePath = resolve(cwd, options.path);
+ if (!existsSync(absolutePath)) {
+ console.log(chalk.red('File not found:') + ` ${options.path}`);
+ process.exitCode = 1;
+ return null;
+ }
+ return options.path;
+ }
+
+ const path = await promptInput('Path to spec file:', '', options);
+
+ if (!path) {
+ console.log(chalk.red('Spec path is required'));
+ process.exitCode = 1;
+ return null;
+ }
+
+ const absolutePath = resolve(cwd, path);
+ if (!existsSync(absolutePath)) {
+ console.log(chalk.red('File not found:') + ` ${path}`);
+ process.exitCode = 1;
+ return null;
+ }
+
+ return path;
+}
+
+/**
+ * Get contract type through prompts or options
+ */
+async function getContractType(
+ cwd: string,
+ specPath: string,
+ options: ContractAddOptions
+): Promise {
+ if (options.type) {
+ return options.type;
+ }
+
+ // Try to auto-detect type
+ const absolutePath = resolve(cwd, specPath);
+ const detectedType = detectSpecType(absolutePath);
+
+ if (detectedType && options.yes) {
+ return detectedType;
+ }
+
+ const typeChoices = CONTRACT_TYPE_CHOICES.map((c) => ({
+ ...c,
+ name: detectedType === c.value ? `${c.name} (detected)` : c.name,
+ }));
+
+ return promptSelect('Contract type:', [...typeChoices], detectedType ?? 'openapi', options);
+}
+
+/**
+ * Get version through prompts or options
+ */
+async function getVersion(options: ContractAddOptions): Promise {
+ if (options.initialVersion) {
+ return options.initialVersion;
+ }
+
+ return promptVersion('Initial version:', DEFAULT_VERSION, options);
+}
+
+/**
+ * Options for the contract list command
+ */
+interface ContractListOptions {
+ /** Output as JSON */
+ json?: boolean;
+}
+
+/**
+ * Contract info for list output
+ */
+interface ContractInfo {
+ name: string;
+ type: ContractType;
+ version: string;
+ path: string;
+}
+
+/**
+ * List contracts
+ */
+export async function contractListCommand(
+ name: string | undefined,
+ options: ContractListOptions = {}
+): Promise {
+ let config;
+ try {
+ config = loadConfig();
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Failed to load configuration:'), message);
+ process.exitCode = 1;
+ return;
+ }
+
+ const contractualDir = findContractualDir(config.configDir);
+ const versionManager = contractualDir ? new VersionManager(contractualDir) : null;
+
+ // Build contract info list
+ let contracts: ContractInfo[] = config.contracts.map((c) => ({
+ name: c.name,
+ type: c.type,
+ version: versionManager?.getVersion(c.name) ?? '0.0.0',
+ path: c.path,
+ }));
+
+ // Filter by name if provided
+ if (name) {
+ contracts = contracts.filter((c) => c.name === name);
+ if (contracts.length === 0) {
+ console.error(chalk.red(`Contract not found: ${name}`));
+ process.exitCode = 1;
+ return;
+ }
+ }
+
+ // Output
+ if (options.json) {
+ console.log(JSON.stringify(contracts, null, 2));
+ return;
+ }
+
+ // Table output
+ if (contracts.length === 0) {
+ console.log(chalk.dim('No contracts configured.'));
+ return;
+ }
+
+ // Calculate column widths
+ const maxNameLen = Math.max(4, ...contracts.map((c) => c.name.length));
+ const maxTypeLen = Math.max(4, ...contracts.map((c) => c.type.length));
+ const maxVersionLen = Math.max(7, ...contracts.map((c) => c.version.length));
+
+ // Header
+ const header =
+ `${'Name'.padEnd(maxNameLen)} ` +
+ `${'Type'.padEnd(maxTypeLen)} ` +
+ `${'Version'.padEnd(maxVersionLen)} ` +
+ `Path`;
+ console.log(chalk.dim(header));
+ console.log(chalk.dim('β'.repeat(header.length + 10)));
+
+ // Rows
+ for (const contract of contracts) {
+ const typeColor = getTypeColor(contract.type);
+ console.log(
+ `${chalk.cyan(contract.name.padEnd(maxNameLen))} ` +
+ `${typeColor(contract.type.padEnd(maxTypeLen))} ` +
+ `${chalk.green(contract.version.padEnd(maxVersionLen))} ` +
+ `${chalk.dim(contract.path)}`
+ );
+ }
+}
+
+/**
+ * Get chalk color function for contract type
+ */
+function getTypeColor(type: ContractType): (text: string) => string {
+ switch (type) {
+ case 'openapi':
+ return chalk.green;
+ case 'asyncapi':
+ return chalk.magenta;
+ case 'json-schema':
+ return chalk.blue;
+ case 'odcs':
+ return chalk.yellow;
+ default:
+ return chalk.white;
+ }
+}
diff --git a/packages/cli/src/commands/diff.command.ts b/packages/cli/src/commands/diff.command.ts
new file mode 100644
index 0000000..e006aed
--- /dev/null
+++ b/packages/cli/src/commands/diff.command.ts
@@ -0,0 +1,71 @@
+/**
+ * Diff Command
+ *
+ * Show all changes between current specs and their last versioned snapshots,
+ * classified by severity.
+ *
+ * Unlike `breaking`, which is a CI gate (exits 1 on breaking changes),
+ * `diff` is informational β it always exits 0 on success.
+ */
+
+import chalk from 'chalk';
+import ora from 'ora';
+import { loadConfig } from '../config/index.js';
+import { diffContracts } from '../core/diff.js';
+import { formatDiffText, formatDiffJson, filterBySeverity } from '../formatters/diff.js';
+
+interface DiffOptions {
+ contract?: string;
+ format?: 'text' | 'json';
+ severity?: 'all' | 'breaking' | 'non-breaking' | 'patch';
+ verbose?: boolean;
+}
+
+/**
+ * Show all changes between current specs and last versioned snapshots
+ */
+export async function diffCommand(options: DiffOptions): Promise {
+ const spinner = ora('Loading configuration...').start();
+
+ let config;
+ try {
+ config = loadConfig();
+ spinner.succeed('Configuration loaded');
+ } catch (error) {
+ spinner.fail('Failed to load configuration');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red(message));
+ process.exitCode = 2;
+ return;
+ }
+
+ const diffSpinner = ora('Comparing specs against snapshots...').start();
+
+ try {
+ const { results } = await diffContracts(config, {
+ contracts: options.contract ? [options.contract] : undefined,
+ includeEmpty: true, // Show "no changes" for contracts with no diff
+ });
+
+ diffSpinner.succeed('Comparison complete');
+ console.log();
+
+ // Apply severity filter
+ const filtered = filterBySeverity(results, options.severity ?? 'all');
+
+ // Output results
+ if (options.format === 'json') {
+ console.log(formatDiffJson(filtered));
+ } else {
+ formatDiffText(filtered, { verbose: options.verbose });
+ }
+
+ // diff always exits 0 on success (it's informational, not a gate)
+ process.exitCode = 0;
+ } catch (error) {
+ diffSpinner.fail('Comparison failed');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Error:'), message);
+ process.exitCode = 3; // Tool execution error
+ }
+}
diff --git a/packages/cli/src/commands/generate.command.ts b/packages/cli/src/commands/generate.command.ts
deleted file mode 100644
index 01d1e2c..0000000
--- a/packages/cli/src/commands/generate.command.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import inquirer from 'inquirer';
-import { createContractCommandHandler } from '@contractual/generators.contract';
-import ora from 'ora';
-import chalk from 'chalk';
-import path from 'node:path';
-import process from 'node:process';
-import {
- generateSpecification,
- getLatestVersion,
- initializePaths,
-} from '@contractual/generators.spec';
-
-export function generateContract() {
- return createContractCommandHandler(
- ora,
- chalk,
- console,
- path.resolve(
- process.cwd(),
- 'contractual',
- 'specs',
- `openapi-v${getLatestVersion(initializePaths().configFilePath)}.yaml`
- )
- ).handle();
-}
-
-export function graduateSpec() {
- return generateSpecification(inquirer);
-}
diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts
new file mode 100644
index 0000000..1263f3e
--- /dev/null
+++ b/packages/cli/src/commands/index.ts
@@ -0,0 +1,6 @@
+export * from './init.command.js';
+export * from './lint.command.js';
+export * from './breaking.command.js';
+export * from './changeset.command.js';
+export * from './version.command.js';
+export * from './status.command.js';
diff --git a/packages/cli/src/commands/init.command.ts b/packages/cli/src/commands/init.command.ts
new file mode 100644
index 0000000..376ba3e
--- /dev/null
+++ b/packages/cli/src/commands/init.command.ts
@@ -0,0 +1,397 @@
+import { existsSync, writeFileSync, readFileSync } from 'node:fs';
+import { join, basename } from 'node:path';
+import fg from 'fast-glob';
+import chalk from 'chalk';
+import ora from 'ora';
+import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
+import { VersionManager } from '@contractual/changesets';
+import {
+ ensureContractualDir,
+ detectSpecType,
+ CONTRACTUAL_DIR,
+ getSnapshotPath,
+} from '../utils/files.js';
+import {
+ promptSelect,
+ promptVersion,
+ promptConfirm,
+ VERSION_CHOICES,
+ VERSIONING_MODE_CHOICES,
+ type PromptOptions,
+} from '../utils/prompts.js';
+import type { ContractDefinition, ContractType, VersioningMode } from '@contractual/types';
+
+/**
+ * Default starting version for new contracts
+ */
+const DEFAULT_VERSION = '0.0.0';
+
+/**
+ * Default versioning mode
+ */
+const DEFAULT_VERSIONING_MODE: VersioningMode = 'independent';
+
+/**
+ * Options for the init command
+ */
+interface InitOptions extends PromptOptions {
+ /** Initial version for contracts */
+ initialVersion?: string;
+ /** Versioning mode */
+ versioning?: VersioningMode;
+ /** Force reinitialize */
+ force?: boolean;
+}
+
+/**
+ * Glob patterns to find spec files
+ */
+const SPEC_PATTERNS = [
+ '**/*.openapi.yaml',
+ '**/*.openapi.yml',
+ '**/*.openapi.json',
+ '**/openapi.yaml',
+ '**/openapi.yml',
+ '**/openapi.json',
+ '**/*.asyncapi.yaml',
+ '**/*.asyncapi.yml',
+ '**/*.asyncapi.json',
+ '**/*.schema.json',
+ '**/*.odcs.yaml',
+ '**/*.odcs.yml',
+];
+
+/**
+ * Directories to ignore when scanning
+ */
+const IGNORE_PATTERNS = [
+ '**/node_modules/**',
+ '**/.git/**',
+ '**/dist/**',
+ '**/build/**',
+ '**/.contractual/**',
+];
+
+/**
+ * Extract contract name from file path
+ * Uses the filename stem without extension patterns
+ */
+function extractContractName(filePath: string): string {
+ const base = basename(filePath);
+
+ // Remove known suffixes and extensions
+ let name = base
+ .replace(/\.openapi\.(ya?ml|json)$/i, '')
+ .replace(/\.asyncapi\.(ya?ml|json)$/i, '')
+ .replace(/\.schema\.json$/i, '')
+ .replace(/\.odcs\.ya?ml$/i, '')
+ .replace(/\.(ya?ml|json)$/i, '');
+
+ // Handle generic names like "openapi" -> use parent directory name
+ if (['openapi', 'asyncapi', 'schema', 'spec', 'api'].includes(name.toLowerCase())) {
+ const parts = filePath.split('/');
+ if (parts.length >= 2) {
+ name = parts[parts.length - 2];
+ }
+ }
+
+ return name;
+}
+
+/**
+ * Get initial version through prompts or options
+ */
+async function getInitialVersion(options: InitOptions): Promise {
+ // If version provided via CLI, use it
+ if (options.initialVersion) {
+ return options.initialVersion;
+ }
+
+ // Prompt for version
+ const versionChoice = await promptSelect(
+ 'Initial version for contracts:',
+ [...VERSION_CHOICES],
+ '0.0.0',
+ options
+ );
+
+ if (versionChoice === 'custom') {
+ return promptVersion('Enter version:', DEFAULT_VERSION, options);
+ }
+
+ return versionChoice;
+}
+
+/**
+ * Get versioning mode through prompts or options
+ */
+async function getVersioningMode(options: InitOptions): Promise {
+ if (options.versioning) {
+ return options.versioning;
+ }
+
+ return promptSelect(
+ 'Versioning mode:',
+ [...VERSIONING_MODE_CHOICES],
+ DEFAULT_VERSIONING_MODE,
+ options
+ );
+}
+
+/**
+ * Initialize Contractual in a repository
+ *
+ * Scans for spec files and generates contractual.yaml configuration
+ */
+export async function initCommand(options: InitOptions = {}): Promise {
+ const cwd = process.cwd();
+ const configPath = join(cwd, 'contractual.yaml');
+ const contractualDir = join(cwd, CONTRACTUAL_DIR);
+
+ // Check if already initialized
+ if (existsSync(configPath) && !options.force) {
+ // Try to handle existing project with uninitialized contracts
+ await handleExistingProject(cwd, configPath, contractualDir, options);
+ return;
+ }
+
+ const spinner = ora('Scanning for spec files...').start();
+
+ try {
+ // Scan for spec files
+ const files = await fg(SPEC_PATTERNS, {
+ cwd,
+ ignore: IGNORE_PATTERNS,
+ absolute: false,
+ onlyFiles: true,
+ });
+
+ spinner.succeed(`Found ${files.length} potential spec file(s)`);
+
+ // Build contract definitions
+ const contracts: ContractDefinition[] = [];
+ const seenNames = new Set();
+
+ for (const filePath of files) {
+ const absolutePath = join(cwd, filePath);
+ const detectedType = detectSpecType(absolutePath);
+
+ if (!detectedType) {
+ continue;
+ }
+
+ let name = extractContractName(filePath);
+
+ // Ensure unique names
+ if (seenNames.has(name)) {
+ let counter = 2;
+ while (seenNames.has(`${name}-${counter}`)) {
+ counter++;
+ }
+ name = `${name}-${counter}`;
+ }
+ seenNames.add(name);
+
+ contracts.push({
+ name,
+ type: detectedType,
+ path: filePath,
+ });
+ }
+
+ if (contracts.length === 0) {
+ console.log(chalk.yellow('\nNo spec files found'));
+ console.log(chalk.dim('\nSupported file patterns:'));
+ console.log(chalk.dim(' - *.openapi.yaml/json'));
+ console.log(chalk.dim(' - *.asyncapi.yaml/json'));
+ console.log(chalk.dim(' - *.schema.json'));
+ console.log(chalk.dim(' - *.odcs.yaml'));
+ console.log(chalk.dim('\nYou can manually create contractual.yaml to define contracts.'));
+ return;
+ }
+
+ // Show found contracts
+ console.log();
+ for (const contract of contracts) {
+ const typeColor = getTypeColor(contract.type);
+ console.log(
+ ` ${chalk.dim('Found:')} ${contract.path} ${chalk.dim('(')}${typeColor(contract.type)}${chalk.dim(')')}`
+ );
+ }
+ console.log();
+
+ // Get version and mode through prompts
+ const initialVersion = await getInitialVersion(options);
+ const versioningMode = await getVersioningMode(options);
+
+ // Generate config
+ const config: Record = {
+ contracts,
+ changeset: {
+ autoDetect: true,
+ requireOnPR: true,
+ },
+ };
+
+ // Only add versioning section if not using defaults
+ if (versioningMode !== 'independent') {
+ config.versioning = {
+ mode: versioningMode,
+ };
+ }
+
+ // Write contractual.yaml
+ const yamlContent = stringifyYaml(config, {
+ lineWidth: 100,
+ singleQuote: true,
+ });
+ writeFileSync(configPath, yamlContent, 'utf-8');
+
+ // Create .contractual directory structure
+ const createdDir = ensureContractualDir(cwd);
+
+ // Create snapshots and set initial versions
+ const versionManager = new VersionManager(createdDir);
+ for (const contract of contracts) {
+ const absolutePath = join(cwd, contract.path);
+ versionManager.setVersion(contract.name, initialVersion, absolutePath);
+ }
+
+ // Print summary
+ console.log();
+ console.log(chalk.green('β') + ' Initialized Contractual');
+ console.log();
+ console.log(chalk.bold('Created:'));
+ console.log(` ${chalk.green('+')} contractual.yaml`);
+ console.log(` ${chalk.green('+')} .contractual/`);
+ console.log(` ${chalk.green('+')} .contractual/changesets/`);
+ console.log(` ${chalk.green('+')} .contractual/snapshots/`);
+ console.log(` ${chalk.green('+')} .contractual/versions.json`);
+
+ console.log();
+ console.log(chalk.bold(`Detected ${contracts.length} contract(s) at v${initialVersion}:`));
+
+ for (const contract of contracts) {
+ const typeColor = getTypeColor(contract.type);
+ console.log(
+ ` ${chalk.cyan(contract.name)} ${chalk.dim('(')}${typeColor(contract.type)}${chalk.dim(')')}`
+ );
+ console.log(` ${chalk.dim(contract.path)}`);
+ }
+
+ if (versioningMode !== 'independent') {
+ console.log();
+ console.log(chalk.dim(`Versioning mode: ${versioningMode}`));
+ }
+
+ console.log();
+ console.log(chalk.dim('Next steps:'));
+ console.log(chalk.dim(' 1. Run `contractual lint` to validate your specs'));
+ console.log(chalk.dim(' 2. Make changes to your specs'));
+ console.log(chalk.dim(' 3. Run `contractual diff` to see changes'));
+ console.log(chalk.dim(' 4. Run `contractual changeset` to record changes'));
+ } catch (error) {
+ spinner.fail('Initialization failed');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red(message));
+ process.exitCode = 1;
+ }
+}
+
+/**
+ * Handle existing project - initialize uninitialized contracts
+ */
+async function handleExistingProject(
+ cwd: string,
+ configPath: string,
+ contractualDir: string,
+ options: InitOptions
+): Promise {
+ // Read existing config
+ const configContent = readFileSync(configPath, 'utf-8');
+ const config = parseYaml(configContent) as { contracts?: ContractDefinition[] };
+
+ if (!config.contracts || config.contracts.length === 0) {
+ console.log(chalk.red('Already initialized:') + ' contractual.yaml exists');
+ console.log(chalk.dim('Use `contractual status` to see current state'));
+ process.exitCode = 1;
+ return;
+ }
+
+ // Ensure .contractual directory exists
+ ensureContractualDir(cwd);
+
+ // Find contracts without snapshots
+ const uninitializedContracts: ContractDefinition[] = [];
+ for (const contract of config.contracts) {
+ const snapshotPath = getSnapshotPath(contract.name, contractualDir);
+ if (!snapshotPath) {
+ uninitializedContracts.push(contract);
+ }
+ }
+
+ if (uninitializedContracts.length === 0) {
+ console.log(chalk.yellow('Already initialized:') + ' contractual.yaml exists');
+ console.log(chalk.dim('All contracts have snapshots.'));
+ console.log(chalk.dim('Use `contractual status` to see current state'));
+ console.log(chalk.dim('Use `--force` to reinitialize'));
+ return;
+ }
+
+ // Show uninitialized contracts
+ console.log(
+ chalk.yellow(`Found ${uninitializedContracts.length} contract(s) without version history:`)
+ );
+ for (const contract of uninitializedContracts) {
+ console.log(
+ ` ${chalk.dim('-')} ${chalk.cyan(contract.name)} ${chalk.dim(`(${contract.type})`)}`
+ );
+ }
+ console.log();
+
+ // Confirm initialization
+ const shouldInitialize = await promptConfirm(
+ `Initialize with version ${DEFAULT_VERSION}?`,
+ true,
+ options
+ );
+
+ if (!shouldInitialize) {
+ console.log(chalk.dim('Skipped initialization'));
+ return;
+ }
+
+ // Initialize uninitialized contracts
+ const versionManager = new VersionManager(contractualDir);
+ for (const contract of uninitializedContracts) {
+ const absolutePath = join(cwd, contract.path);
+ if (!existsSync(absolutePath)) {
+ console.log(
+ chalk.yellow(` Skipped ${contract.name}: spec file not found at ${contract.path}`)
+ );
+ continue;
+ }
+ versionManager.setVersion(contract.name, DEFAULT_VERSION, absolutePath);
+ console.log(
+ chalk.green('β') + ` Initialized ${chalk.cyan(contract.name)} at v${DEFAULT_VERSION}`
+ );
+ }
+}
+
+/**
+ * Get chalk color function for contract type
+ */
+function getTypeColor(type: ContractType): (text: string) => string {
+ switch (type) {
+ case 'openapi':
+ return chalk.green;
+ case 'asyncapi':
+ return chalk.magenta;
+ case 'json-schema':
+ return chalk.blue;
+ case 'odcs':
+ return chalk.yellow;
+ default:
+ return chalk.white;
+ }
+}
diff --git a/packages/cli/src/commands/lint.command.ts b/packages/cli/src/commands/lint.command.ts
new file mode 100644
index 0000000..a2a7ca1
--- /dev/null
+++ b/packages/cli/src/commands/lint.command.ts
@@ -0,0 +1,224 @@
+import chalk from 'chalk';
+import ora from 'ora';
+import { loadConfig } from '../config/index.js';
+import { getLinter as getRegisteredLinter } from '../governance/index.js';
+import { printSuccess, printError, printWarning } from '../utils/output.js';
+import type { LintResult, LintFn, ResolvedContract } from '@contractual/types';
+
+/**
+ * Options for the lint command
+ */
+export interface LintOptions {
+ /** Filter to specific contract name */
+ contract?: string;
+ /** Output format */
+ format?: 'text' | 'json';
+ /** Exit 1 on warnings */
+ failOnWarn?: boolean;
+}
+
+/**
+ * Result type for linter lookup
+ */
+type LinterLookupResult =
+ | { status: 'disabled' }
+ | { status: 'not-found'; type: string }
+ | { status: 'found'; linter: LintFn };
+
+/**
+ * Get linter for a contract using the governance registry
+ */
+function getLinterForContract(contract: ResolvedContract): LinterLookupResult {
+ // Check if linting is explicitly disabled
+ if (contract.lint === false) {
+ return { status: 'disabled' };
+ }
+
+ // Use the governance registry to get the linter
+ const linter = getRegisteredLinter(contract.type, contract.lint);
+
+ if (linter === null) {
+ return { status: 'disabled' };
+ }
+
+ if (!linter) {
+ return { status: 'not-found', type: contract.type };
+ }
+
+ return { status: 'found', linter };
+}
+
+/**
+ * Run linters for all configured contracts
+ */
+export async function lintCommand(options: LintOptions = {}): Promise {
+ const { contract: filterContract, format = 'text', failOnWarn = false } = options;
+
+ try {
+ // Load config
+ const config = loadConfig();
+
+ // Filter contracts if specified
+ let contracts = config.contracts;
+ if (filterContract) {
+ contracts = contracts.filter((c) => c.name === filterContract);
+ if (contracts.length === 0) {
+ if (format === 'json') {
+ console.log(JSON.stringify({ error: `Contract "${filterContract}" not found` }));
+ } else {
+ printError(`Contract "${filterContract}" not found`);
+ }
+ process.exitCode = 1;
+ return;
+ }
+ }
+
+ if (contracts.length === 0) {
+ if (format === 'json') {
+ console.log(JSON.stringify({ results: [], errors: 0, warnings: 0 }));
+ } else {
+ printWarning('No contracts configured');
+ }
+ return;
+ }
+
+ const results: LintResult[] = [];
+ const spinner = format === 'text' ? ora('Linting contracts...').start() : null;
+
+ for (const contract of contracts) {
+ if (spinner) {
+ spinner.text = `Linting ${contract.name}...`;
+ }
+
+ const linterResult = getLinterForContract(contract);
+
+ // Linting explicitly disabled
+ if (linterResult.status === 'disabled') {
+ if (format === 'text') {
+ spinner?.stopAndPersist({
+ symbol: chalk.dim('-'),
+ text: `${contract.name}: ${chalk.dim('linting disabled')}`,
+ });
+ spinner?.start();
+ }
+ continue;
+ }
+
+ // No linter registered for this type
+ if (linterResult.status === 'not-found') {
+ if (format === 'text') {
+ spinner?.stopAndPersist({
+ symbol: chalk.yellow('!'),
+ text: `${contract.name}: ${chalk.yellow(`no linter available for ${linterResult.type}`)}`,
+ });
+ spinner?.start();
+ }
+ continue;
+ }
+
+ try {
+ const result = await linterResult.linter(contract.absolutePath);
+ results.push({
+ ...result,
+ contract: contract.name,
+ });
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Linter execution failed';
+ results.push({
+ contract: contract.name,
+ specPath: contract.absolutePath,
+ errors: [
+ {
+ path: '',
+ message,
+ severity: 'error',
+ },
+ ],
+ warnings: [],
+ });
+ }
+ }
+
+ spinner?.stop();
+
+ // Calculate totals
+ const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
+ const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0);
+
+ // Output results
+ if (format === 'json') {
+ console.log(
+ JSON.stringify(
+ {
+ results,
+ errors: totalErrors,
+ warnings: totalWarnings,
+ },
+ null,
+ 2
+ )
+ );
+ } else {
+ // Text format output
+ console.log();
+
+ for (const result of results) {
+ const hasErrors = result.errors.length > 0;
+ const hasWarnings = result.warnings.length > 0;
+
+ if (!hasErrors && !hasWarnings) {
+ printSuccess(`${result.contract}: No issues found`);
+ continue;
+ }
+
+ // Print contract header
+ const errorCount = result.errors.length;
+ const warningCount = result.warnings.length;
+ const summary = [];
+ if (errorCount > 0) summary.push(chalk.red(`${errorCount} error(s)`));
+ if (warningCount > 0) summary.push(chalk.yellow(`${warningCount} warning(s)`));
+
+ console.log(`${chalk.bold(result.contract)}: ${summary.join(', ')}`);
+
+ // Print errors
+ for (const error of result.errors) {
+ const location = error.path ? chalk.dim(`[${error.path}]`) : '';
+ const rule = error.rule ? chalk.dim(`(${error.rule})`) : '';
+ console.log(` ${chalk.red('error')} ${location} ${error.message} ${rule}`);
+ }
+
+ // Print warnings
+ for (const warning of result.warnings) {
+ const location = warning.path ? chalk.dim(`[${warning.path}]`) : '';
+ const rule = warning.rule ? chalk.dim(`(${warning.rule})`) : '';
+ console.log(` ${chalk.yellow('warn')} ${location} ${warning.message} ${rule}`);
+ }
+
+ console.log();
+ }
+
+ // Summary
+ if (results.length > 0) {
+ console.log(
+ chalk.dim(
+ `Checked ${results.length} contract(s): ` +
+ `${totalErrors} error(s), ${totalWarnings} warning(s)`
+ )
+ );
+ }
+ }
+
+ // Exit with error code if there were errors (or warnings if --fail-on-warn)
+ if (totalErrors > 0 || (failOnWarn && totalWarnings > 0)) {
+ process.exitCode = 1;
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ if (options.format === 'json') {
+ console.log(JSON.stringify({ error: message }));
+ } else {
+ printError(message);
+ }
+ process.exitCode = 1;
+ }
+}
diff --git a/packages/cli/src/commands/pre.command.ts b/packages/cli/src/commands/pre.command.ts
new file mode 100644
index 0000000..e962aa6
--- /dev/null
+++ b/packages/cli/src/commands/pre.command.ts
@@ -0,0 +1,172 @@
+import chalk from 'chalk';
+import { VersionManager, PreReleaseManager } from '@contractual/changesets';
+import { findContractualDir } from '../utils/files.js';
+
+/**
+ * Enter pre-release mode
+ * @param tag - The pre-release tag (e.g., "alpha", "beta", "rc")
+ */
+export async function preEnterCommand(tag: string): Promise {
+ const cwd = process.cwd();
+ const contractualDir = findContractualDir(cwd);
+
+ if (!contractualDir) {
+ console.error(chalk.red('No .contractual directory found. Run `contractual init` first.'));
+ process.exitCode = 1;
+ return;
+ }
+
+ try {
+ const versionManager = new VersionManager(contractualDir);
+ const preManager = new PreReleaseManager(contractualDir);
+
+ if (preManager.isActive()) {
+ const state = preManager.getState();
+ console.log(chalk.yellow('Already in pre-release mode:') + ` ${state?.tag}`);
+ console.log(chalk.dim('Run `contractual pre exit` to leave pre-release mode first.'));
+ process.exitCode = 1;
+ return;
+ }
+
+ preManager.enter(tag, versionManager);
+
+ console.log(chalk.green('β') + ` Entered pre-release mode: ${chalk.cyan(tag)}`);
+ console.log();
+ console.log(chalk.bold('Created:'));
+ console.log(` ${chalk.green('+')} .contractual/pre.json`);
+ console.log();
+ console.log(chalk.dim(`Next versions will use ${tag} identifier (e.g., 2.0.0-${tag}.0)`));
+ console.log(
+ chalk.dim('Run `contractual version` to apply changesets with pre-release versions.')
+ );
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Failed to enter pre-release mode:'), message);
+ process.exitCode = 1;
+ }
+}
+
+/**
+ * Exit pre-release mode
+ */
+export async function preExitCommand(): Promise {
+ const cwd = process.cwd();
+ const contractualDir = findContractualDir(cwd);
+
+ if (!contractualDir) {
+ console.error(chalk.red('No .contractual directory found. Run `contractual init` first.'));
+ process.exitCode = 1;
+ return;
+ }
+
+ try {
+ const versionManager = new VersionManager(contractualDir);
+ const preManager = new PreReleaseManager(contractualDir);
+
+ if (!preManager.isActive()) {
+ console.log(chalk.yellow('Not in pre-release mode.'));
+ return;
+ }
+
+ const state = preManager.getState();
+ const currentVersions = versionManager.getAllVersions();
+
+ // Show what will change
+ console.log(chalk.bold('Exiting pre-release mode'));
+ console.log();
+
+ const hasPreReleaseVersions = Object.entries(currentVersions).some(([_, version]) =>
+ version.includes('-')
+ );
+
+ if (hasPreReleaseVersions) {
+ console.log(chalk.dim('Current pre-release versions:'));
+ for (const [contract, version] of Object.entries(currentVersions)) {
+ if (version.includes('-')) {
+ // Extract base version
+ const baseVersion = version.split('-')[0];
+ console.log(
+ ` ${chalk.cyan(contract)}: ${chalk.gray(version)} β ${chalk.green(baseVersion)}`
+ );
+ }
+ }
+ console.log();
+ console.log(chalk.dim('Run `contractual version` after exiting to finalize versions.'));
+ }
+
+ preManager.exit();
+
+ console.log();
+ console.log(chalk.green('β') + ' Exited pre-release mode');
+ console.log();
+ console.log(chalk.bold('Removed:'));
+ console.log(` ${chalk.red('-')} .contractual/pre.json`);
+
+ if (state) {
+ console.log();
+ console.log(chalk.dim(`Pre-release tag was: ${state.tag}`));
+ console.log(chalk.dim(`Entered at: ${new Date(state.enteredAt).toLocaleString()}`));
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Failed to exit pre-release mode:'), message);
+ process.exitCode = 1;
+ }
+}
+
+/**
+ * Show pre-release status
+ */
+export async function preStatusCommand(): Promise {
+ const cwd = process.cwd();
+ const contractualDir = findContractualDir(cwd);
+
+ if (!contractualDir) {
+ console.error(chalk.red('No .contractual directory found. Run `contractual init` first.'));
+ process.exitCode = 1;
+ return;
+ }
+
+ const preManager = new PreReleaseManager(contractualDir);
+
+ if (!preManager.isActive()) {
+ console.log(chalk.dim('Not in pre-release mode.'));
+ console.log(chalk.dim('Run `contractual pre enter ` to enter pre-release mode.'));
+ return;
+ }
+
+ const state = preManager.getState();
+ if (!state) {
+ console.log(chalk.yellow('Pre-release state file is corrupted.'));
+ console.log(chalk.dim('Run `contractual pre exit` to reset.'));
+ return;
+ }
+
+ const versionManager = new VersionManager(contractualDir);
+ const currentVersions = versionManager.getAllVersions();
+
+ console.log(chalk.bold('Pre-release Status'));
+ console.log();
+ console.log(` ${chalk.dim('Tag:')} ${chalk.cyan(state.tag)}`);
+ console.log(` ${chalk.dim('Since:')} ${new Date(state.enteredAt).toLocaleString()}`);
+
+ // Show version changes since entering pre-release
+ const changedContracts = Object.entries(currentVersions).filter(([name, version]) => {
+ const initial = state.initialVersions[name];
+ return initial && initial !== version;
+ });
+
+ if (changedContracts.length > 0) {
+ console.log();
+ console.log(chalk.bold('Version changes since entering pre-release:'));
+ for (const [name, version] of changedContracts) {
+ const initial = state.initialVersions[name];
+ console.log(` ${chalk.cyan(name)}: ${chalk.gray(initial)} β ${chalk.green(version)}`);
+ }
+ }
+
+ console.log();
+ console.log(chalk.dim('Commands:'));
+ console.log(chalk.dim(' contractual version Apply changesets with pre-release versions'));
+ console.log(chalk.dim(' contractual pre exit Exit pre-release mode'));
+}
diff --git a/packages/cli/src/commands/status.command.ts b/packages/cli/src/commands/status.command.ts
new file mode 100644
index 0000000..1782947
--- /dev/null
+++ b/packages/cli/src/commands/status.command.ts
@@ -0,0 +1,144 @@
+import { existsSync, readFileSync } from 'node:fs';
+import { join } from 'node:path';
+import chalk from 'chalk';
+import { loadConfig } from '../config/index.js';
+import { findContractualDir, VERSIONS_FILE, CHANGESETS_DIR } from '../utils/files.js';
+import { aggregateBumps, incrementVersion, readChangesets } from '@contractual/changesets';
+import type { VersionsFile, ChangesetFile } from '@contractual/types';
+
+/**
+ * Read versions.json file
+ */
+function readVersions(contractualDir: string): VersionsFile {
+ const versionsPath = join(contractualDir, VERSIONS_FILE);
+
+ if (!existsSync(versionsPath)) {
+ return {};
+ }
+
+ try {
+ const content = readFileSync(versionsPath, 'utf-8');
+ return JSON.parse(content) as VersionsFile;
+ } catch {
+ return {};
+ }
+}
+
+/**
+ * Show current state - versions, pending changesets, projected bumps
+ */
+export async function statusCommand(): Promise {
+ try {
+ // Load config
+ const config = loadConfig();
+ const contractualDir = findContractualDir();
+
+ if (!contractualDir) {
+ console.log(chalk.red('Not initialized:') + ' .contractual directory not found');
+ console.log(chalk.dim('Run `contractual init` to get started'));
+ process.exitCode = 1;
+ return;
+ }
+
+ // Read versions
+ const versions = readVersions(contractualDir);
+
+ // Read pending changesets
+ const changesetsDir = join(contractualDir, CHANGESETS_DIR);
+ let changesets: ChangesetFile[] = [];
+ try {
+ changesets = await readChangesets(changesetsDir);
+ } catch (error) {
+ // If parsing fails, show a warning but continue
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.warn(chalk.yellow(`Warning: ${message}`));
+ }
+
+ // Calculate projected bumps
+ const projectedBumps = aggregateBumps(changesets);
+
+ // Print header
+ console.log(chalk.bold('\nContractual Status\n'));
+
+ // Print contract versions
+ console.log(chalk.bold.underline('Contracts'));
+ console.log();
+
+ if (config.contracts.length === 0) {
+ console.log(chalk.dim(' No contracts configured'));
+ } else {
+ for (const contract of config.contracts) {
+ const versionEntry = versions[contract.name];
+ const currentVersion = versionEntry?.version ?? '0.0.0';
+ const bump = projectedBumps[contract.name];
+
+ let projectedVersion: string | null = null;
+ if (bump) {
+ projectedVersion = incrementVersion(currentVersion, bump);
+ }
+
+ // Contract name and type
+ const typeLabel = chalk.dim(`(${contract.type})`);
+ console.log(` ${chalk.cyan(contract.name)} ${typeLabel}`);
+
+ // Version info
+ const versionLabel = versionEntry
+ ? chalk.green(`v${currentVersion}`)
+ : chalk.dim('v0.0.0 (unreleased)');
+
+ if (projectedVersion) {
+ const bumpColor =
+ bump === 'major' ? chalk.red : bump === 'minor' ? chalk.yellow : chalk.green;
+ console.log(
+ ` ${versionLabel} ${chalk.dim('->')} ${bumpColor(`v${projectedVersion}`)} ${chalk.dim(`(${bump})`)}`
+ );
+ } else {
+ console.log(` ${versionLabel}`);
+ }
+
+ // Release date
+ if (versionEntry?.released) {
+ const date = new Date(versionEntry.released).toLocaleDateString();
+ console.log(` ${chalk.dim(`Released: ${date}`)}`);
+ }
+
+ console.log();
+ }
+ }
+
+ // Print pending changesets
+ console.log(chalk.bold.underline('Pending Changesets'));
+ console.log();
+
+ if (changesets.length === 0) {
+ console.log(chalk.dim(' No pending changesets'));
+ console.log(chalk.dim(' Run `contractual add` to create one'));
+ } else {
+ console.log(` ${chalk.yellow(changesets.length.toString())} changeset(s) pending\n`);
+
+ for (const changeset of changesets) {
+ console.log(` ${chalk.dim('-')} ${changeset.filename}`);
+
+ for (const [contract, bump] of Object.entries(changeset.bumps)) {
+ const bumpColor =
+ bump === 'major' ? chalk.red : bump === 'minor' ? chalk.yellow : chalk.green;
+ console.log(` ${chalk.cyan(contract)}: ${bumpColor(bump)}`);
+ }
+ }
+ }
+
+ console.log();
+
+ // Summary
+ const hasProjectedBumps = Object.keys(projectedBumps).length > 0;
+ if (hasProjectedBumps) {
+ console.log(
+ chalk.dim('Run `contractual version` to apply pending changesets and bump versions')
+ );
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red('Error:'), message);
+ process.exitCode = 1;
+ }
+}
diff --git a/packages/cli/src/commands/version.command.ts b/packages/cli/src/commands/version.command.ts
new file mode 100644
index 0000000..c20dae4
--- /dev/null
+++ b/packages/cli/src/commands/version.command.ts
@@ -0,0 +1,336 @@
+import { existsSync, unlinkSync } from 'node:fs';
+import { join } from 'node:path';
+import chalk from 'chalk';
+import ora from 'ora';
+import { loadConfig } from '../config/index.js';
+import { findContractualDir, CHANGESETS_DIR } from '../utils/files.js';
+import { promptConfirm, type PromptOptions } from '../utils/prompts.js';
+import {
+ VersionManager,
+ PreReleaseManager,
+ readChangesets,
+ aggregateBumps,
+ extractContractChanges,
+ appendChangelog,
+ incrementVersion,
+ incrementVersionWithPreRelease,
+ updateSpecVersion,
+} from '@contractual/changesets';
+import type { BumpResult, BumpType } from '@contractual/types';
+
+/**
+ * Options for the version command
+ */
+interface VersionOptions extends PromptOptions {
+ /** Preview without applying */
+ dryRun?: boolean;
+ /** Output JSON (implies --yes) */
+ json?: boolean;
+ /** Skip updating version field inside spec files */
+ syncVersion?: boolean;
+}
+
+/**
+ * Pending version bump info
+ */
+interface PendingBump {
+ contract: string;
+ currentVersion: string;
+ nextVersion: string;
+ bumpType: BumpType;
+}
+
+/**
+ * Consume changesets and bump versions
+ */
+export async function versionCommand(options: VersionOptions = {}): Promise {
+ // JSON output implies --yes (no prompts)
+ if (options.json) {
+ options.yes = true;
+ }
+
+ const spinner = ora('Loading configuration...').start();
+
+ let config;
+ try {
+ config = loadConfig();
+ spinner.succeed('Configuration loaded');
+ } catch (error) {
+ spinner.fail('Failed to load configuration');
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ console.error(chalk.red(message));
+ process.exit(1);
+ }
+
+ const contractualDir = findContractualDir(config.configDir);
+ if (!contractualDir) {
+ console.error(chalk.red('No .contractual directory found. Run `contractual init` first.'));
+ process.exit(1);
+ }
+
+ // Read all changesets
+ const readSpinner = ora('Reading changesets...').start();
+ const changesetsDir = join(contractualDir, CHANGESETS_DIR);
+ const changesets = await readChangesets(changesetsDir);
+
+ if (changesets.length === 0) {
+ readSpinner.succeed('No pending changesets');
+ if (options.json) {
+ console.log(JSON.stringify({ bumps: [], changesets: 0 }, null, 2));
+ } else {
+ console.log(chalk.gray('Nothing to version.'));
+ }
+ process.exit(0);
+ }
+
+ readSpinner.succeed(`Found ${changesets.length} changeset(s)`);
+
+ // Aggregate bumps (highest wins per contract)
+ const aggregatedBumps = aggregateBumps(changesets);
+
+ if (Object.keys(aggregatedBumps).length === 0) {
+ if (options.json) {
+ console.log(JSON.stringify({ bumps: [], changesets: changesets.length }, null, 2));
+ } else {
+ console.log(chalk.gray('No version bumps required.'));
+ }
+ process.exit(0);
+ }
+
+ // Initialize version manager for reading current versions
+ const versionManager = new VersionManager(contractualDir);
+ const preManager = new PreReleaseManager(contractualDir);
+ const preReleaseTag = preManager.getTag();
+
+ // Calculate pending bumps (preview)
+ const pendingBumps: PendingBump[] = [];
+
+ for (const [contractName, bumpType] of Object.entries(aggregatedBumps)) {
+ const contract = config.contracts.find((c) => c.name === contractName);
+ if (!contract) {
+ continue;
+ }
+
+ const currentVersion = versionManager.getVersion(contractName) ?? '0.0.0';
+ const nextVersion = preReleaseTag
+ ? incrementVersionWithPreRelease(currentVersion, bumpType, preReleaseTag)
+ : incrementVersion(currentVersion, bumpType);
+
+ pendingBumps.push({
+ contract: contractName,
+ currentVersion,
+ nextVersion,
+ bumpType,
+ });
+ }
+
+ // Show pre-release mode notice
+ if (preReleaseTag && !options.json) {
+ console.log(chalk.cyan(`Pre-release mode: ${preReleaseTag}`));
+ }
+
+ // Show preview
+ if (options.json) {
+ if (options.dryRun) {
+ console.log(
+ JSON.stringify(
+ {
+ dryRun: true,
+ bumps: pendingBumps.map((b) => ({
+ contract: b.contract,
+ current: b.currentVersion,
+ next: b.nextVersion,
+ type: b.bumpType,
+ })),
+ changesets: changesets.length,
+ },
+ null,
+ 2
+ )
+ );
+ return;
+ }
+ } else {
+ printPreviewTable(pendingBumps);
+
+ if (options.dryRun) {
+ console.log();
+ console.log(chalk.dim('Dry run - no changes applied'));
+ return;
+ }
+ }
+
+ // Confirm before applying (unless --yes)
+ if (!options.json) {
+ const shouldApply = await promptConfirm('Apply these version bumps?', true, options);
+
+ if (!shouldApply) {
+ console.log(chalk.dim('Cancelled'));
+ return;
+ }
+ }
+
+ // Apply version bumps
+ const bumpSpinner = options.json ? null : ora('Applying version bumps...').start();
+ const bumpResults: BumpResult[] = [];
+ const consumedChangesetPaths: string[] = [];
+
+ for (const [contractName, bumpType] of Object.entries(aggregatedBumps)) {
+ const contract = config.contracts.find((c) => c.name === contractName);
+ if (!contract) {
+ if (!options.json) {
+ console.warn(
+ chalk.yellow(`Warning: Contract "${contractName}" not found in config, skipping.`)
+ );
+ }
+ continue;
+ }
+
+ const oldVersion = versionManager.getVersion(contractName) ?? '0.0.0';
+ let newVersion: string;
+
+ const shouldSyncVersion = options.syncVersion !== false && contract.syncVersion !== false;
+
+ if (preReleaseTag) {
+ // Use pre-release version increment
+ newVersion = incrementVersionWithPreRelease(oldVersion, bumpType, preReleaseTag);
+ if (shouldSyncVersion) {
+ updateSpecVersion(contract.absolutePath, newVersion, contract.type);
+ }
+ versionManager.setVersion(contractName, newVersion, contract.absolutePath);
+ } else {
+ // Normal bump β compute version first, update spec, then bump (which copies to snapshots)
+ newVersion = incrementVersion(oldVersion, bumpType);
+ if (shouldSyncVersion) {
+ updateSpecVersion(contract.absolutePath, newVersion, contract.type);
+ }
+ versionManager.bump(contractName, bumpType, contract.absolutePath);
+ }
+
+ // Extract changes text from changesets for this contract
+ const changes = extractContractChanges(changesets, contractName);
+
+ bumpResults.push({
+ contract: contractName,
+ oldVersion,
+ newVersion,
+ bumpType,
+ changes,
+ });
+ }
+
+ bumpSpinner?.succeed('Version bumps applied');
+
+ // Append to CHANGELOG.md
+ const changelogSpinner = options.json ? null : ora('Updating changelog...').start();
+ const changelogPath = join(config.configDir, 'CHANGELOG.md');
+ try {
+ appendChangelog(changelogPath, bumpResults);
+ changelogSpinner?.succeed('Changelog updated');
+ } catch (error) {
+ const message = error instanceof Error ? error.message : 'Unknown error';
+ changelogSpinner?.warn(`Failed to update changelog: ${message}`);
+ }
+
+ // Delete consumed changeset files
+ const cleanupSpinner = options.json ? null : ora('Cleaning up changesets...').start();
+
+ for (const changeset of changesets) {
+ const changesetPath = join(changesetsDir, changeset.filename);
+ try {
+ if (existsSync(changesetPath)) {
+ unlinkSync(changesetPath);
+ consumedChangesetPaths.push(changeset.filename);
+ }
+ } catch {
+ // Ignore cleanup errors
+ }
+ }
+ cleanupSpinner?.succeed(`Removed ${consumedChangesetPaths.length} changeset(s)`);
+
+ // Print summary
+ if (options.json) {
+ console.log(
+ JSON.stringify(
+ {
+ bumps: bumpResults.map((r) => ({
+ contract: r.contract,
+ old: r.oldVersion,
+ new: r.newVersion,
+ type: r.bumpType,
+ })),
+ changesets: consumedChangesetPaths.length,
+ },
+ null,
+ 2
+ )
+ );
+ } else {
+ console.log();
+ console.log(chalk.bold('Version Summary:'));
+ console.log();
+
+ for (const result of bumpResults) {
+ console.log(
+ ` ${chalk.cyan(result.contract)}: ` +
+ `${chalk.gray(result.oldVersion)} -> ${chalk.green(result.newVersion)} ` +
+ `(${result.bumpType})`
+ );
+ }
+
+ console.log();
+ console.log(chalk.green('Done!'), `${bumpResults.length} contract(s) versioned.`);
+ }
+}
+
+/**
+ * Print a preview table of pending version bumps
+ */
+function printPreviewTable(bumps: PendingBump[]): void {
+ console.log();
+ console.log(chalk.bold('Pending version bumps:'));
+ console.log();
+
+ // Calculate column widths
+ const maxContractLen = Math.max(8, ...bumps.map((b) => b.contract.length));
+ const maxCurrentLen = Math.max(7, ...bumps.map((b) => b.currentVersion.length));
+ const maxNextLen = Math.max(4, ...bumps.map((b) => b.nextVersion.length));
+
+ // Header
+ const header =
+ ` ${'Contract'.padEnd(maxContractLen)} ` +
+ `${'Current'.padEnd(maxCurrentLen)} ` +
+ `${'β'} ` +
+ `${'Next'.padEnd(maxNextLen)} ` +
+ `Reason`;
+ console.log(chalk.dim(header));
+ console.log(chalk.dim(' ' + 'β'.repeat(header.length - 2)));
+
+ // Rows
+ for (const bump of bumps) {
+ const reason = getBumpReason(bump.bumpType);
+ console.log(
+ ` ${chalk.cyan(bump.contract.padEnd(maxContractLen))} ` +
+ `${chalk.gray(bump.currentVersion.padEnd(maxCurrentLen))} ` +
+ `${chalk.dim('β')} ` +
+ `${chalk.green(bump.nextVersion.padEnd(maxNextLen))} ` +
+ `${reason}`
+ );
+ }
+}
+
+/**
+ * Get human-readable reason for bump type
+ */
+function getBumpReason(bumpType: BumpType): string {
+ switch (bumpType) {
+ case 'major':
+ return chalk.red('major (breaking)');
+ case 'minor':
+ return chalk.yellow('minor (feature)');
+ case 'patch':
+ return chalk.dim('patch (fix)');
+ default:
+ return bumpType;
+ }
+}
diff --git a/packages/cli/src/config/index.ts b/packages/cli/src/config/index.ts
new file mode 100644
index 0000000..1febe5a
--- /dev/null
+++ b/packages/cli/src/config/index.ts
@@ -0,0 +1,2 @@
+export * from './loader.js';
+export * from './validator.js';
diff --git a/packages/cli/src/config/loader.ts b/packages/cli/src/config/loader.ts
new file mode 100644
index 0000000..7a8d65d
--- /dev/null
+++ b/packages/cli/src/config/loader.ts
@@ -0,0 +1,147 @@
+import { existsSync, readFileSync } from 'node:fs';
+import { dirname, join, resolve } from 'node:path';
+import { parse as parseYaml } from 'yaml';
+import fg from 'fast-glob';
+import type { ContractualConfig, ResolvedConfig, ResolvedContract } from '@contractual/types';
+import { validateConfig, formatValidationErrors } from './validator.js';
+
+/**
+ * Config file names to search for
+ */
+const CONFIG_FILENAMES = ['contractual.yaml', 'contractual.yml'];
+
+/**
+ * Error thrown when config cannot be loaded
+ */
+export class ConfigError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'ConfigError';
+ }
+}
+
+/**
+ * Find contractual.yaml by walking up from the given directory
+ */
+export function findConfigFile(startDir: string = process.cwd()): string | null {
+ let currentDir = resolve(startDir);
+ const root = dirname(currentDir);
+
+ while (currentDir !== root) {
+ for (const filename of CONFIG_FILENAMES) {
+ const configPath = join(currentDir, filename);
+ if (existsSync(configPath)) {
+ return configPath;
+ }
+ }
+ const parentDir = dirname(currentDir);
+ if (parentDir === currentDir) break;
+ currentDir = parentDir;
+ }
+
+ // Check root directory too
+ for (const filename of CONFIG_FILENAMES) {
+ const configPath = join(currentDir, filename);
+ if (existsSync(configPath)) {
+ return configPath;
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Parse YAML config file
+ */
+export function parseConfigFile(configPath: string): unknown {
+ const content = readFileSync(configPath, 'utf-8');
+
+ try {
+ return parseYaml(content);
+ } catch (err) {
+ const message = err instanceof Error ? err.message : 'Unknown parse error';
+ throw new ConfigError(`Failed to parse ${configPath}: ${message}`);
+ }
+}
+
+/**
+ * Resolve contract paths to absolute paths
+ */
+export function resolveContractPaths(
+ config: ContractualConfig,
+ configDir: string
+): ResolvedContract[] {
+ const resolved: ResolvedContract[] = [];
+
+ for (const contract of config.contracts) {
+ const pattern = contract.path;
+ const absolutePattern = resolve(configDir, pattern);
+
+ // Check if it's a glob pattern
+ if (pattern.includes('*')) {
+ const matches = fg.sync(absolutePattern, { onlyFiles: true });
+ if (matches.length === 0) {
+ console.warn(
+ `Warning: No files matched pattern "${pattern}" for contract "${contract.name}"`
+ );
+ }
+ // For glob patterns, use the first match as the primary path
+ // In the future, we might support multiple specs per contract
+ if (matches.length > 0) {
+ resolved.push({
+ ...contract,
+ absolutePath: matches[0],
+ });
+ }
+ } else {
+ // Direct file path
+ if (!existsSync(absolutePattern)) {
+ console.warn(`Warning: File not found "${pattern}" for contract "${contract.name}"`);
+ }
+ resolved.push({
+ ...contract,
+ absolutePath: absolutePattern,
+ });
+ }
+ }
+
+ return resolved;
+}
+
+/**
+ * Load and validate config from a file path
+ */
+export function loadConfigFromPath(configPath: string): ResolvedConfig {
+ const parsed = parseConfigFile(configPath);
+
+ const validation = validateConfig(parsed);
+ if (!validation.valid) {
+ throw new ConfigError(
+ `Invalid configuration in ${configPath}:\n${formatValidationErrors(validation.errors)}`
+ );
+ }
+
+ const config = parsed as ContractualConfig;
+ const configDir = dirname(configPath);
+ const resolvedContracts = resolveContractPaths(config, configDir);
+
+ return {
+ ...config,
+ contracts: resolvedContracts,
+ configDir,
+ configPath,
+ };
+}
+
+/**
+ * Load config by searching from the current directory
+ */
+export function loadConfig(startDir?: string): ResolvedConfig {
+ const configPath = findConfigFile(startDir);
+
+ if (!configPath) {
+ throw new ConfigError('No contractual.yaml found. Run `contractual init` to get started.');
+ }
+
+ return loadConfigFromPath(configPath);
+}
diff --git a/packages/cli/src/config/schema.json b/packages/cli/src/config/schema.json
new file mode 100644
index 0000000..2b59b0d
--- /dev/null
+++ b/packages/cli/src/config/schema.json
@@ -0,0 +1,126 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://contractual.dev/schemas/config.json",
+ "title": "Contractual Configuration",
+ "description": "Configuration file for Contractual schema contract lifecycle orchestrator",
+ "type": "object",
+ "required": ["contracts"],
+ "properties": {
+ "contracts": {
+ "type": "array",
+ "description": "List of contract definitions",
+ "minItems": 1,
+ "items": {
+ "type": "object",
+ "required": ["name", "type", "path"],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Unique identifier for the contract",
+ "pattern": "^[a-z][a-z0-9-]*$"
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of schema",
+ "enum": ["openapi", "json-schema", "asyncapi", "odcs"]
+ },
+ "path": {
+ "type": "string",
+ "description": "Path to spec file (can be glob pattern)"
+ },
+ "lint": {
+ "oneOf": [
+ { "type": "string", "description": "Linter tool name or custom command" },
+ { "type": "boolean", "const": false, "description": "Disable linting" }
+ ]
+ },
+ "breaking": {
+ "oneOf": [
+ { "type": "string", "description": "Differ tool name or custom command" },
+ { "type": "boolean", "const": false, "description": "Disable breaking change detection" }
+ ]
+ },
+ "syncVersion": {
+ "type": "boolean",
+ "description": "Sync version field inside the spec file on version bump (default: true). Set to false to skip.",
+ "default": true
+ },
+ "generate": {
+ "type": "array",
+ "description": "Output generation commands",
+ "items": { "type": "string" }
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "versioning": {
+ "type": "object",
+ "description": "Versioning configuration",
+ "properties": {
+ "mode": {
+ "type": "string",
+ "enum": ["independent", "fixed"],
+ "description": "Versioning mode: independent (each contract separate) or fixed (all share same version)",
+ "default": "independent"
+ }
+ },
+ "additionalProperties": false
+ },
+ "changeset": {
+ "type": "object",
+ "description": "Changeset behavior configuration",
+ "properties": {
+ "autoDetect": {
+ "type": "boolean",
+ "description": "Auto-detect change classifications",
+ "default": true
+ },
+ "requireOnPR": {
+ "type": "boolean",
+ "description": "Require changeset for spec changes in PRs",
+ "default": true
+ }
+ },
+ "additionalProperties": false
+ },
+ "ai": {
+ "type": "object",
+ "description": "AI/LLM integration configuration",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "enum": ["anthropic"],
+ "default": "anthropic"
+ },
+ "model": {
+ "type": "string",
+ "description": "Model to use"
+ },
+ "features": {
+ "type": "object",
+ "properties": {
+ "explain": {
+ "type": "boolean",
+ "description": "PR change explanations",
+ "default": true
+ },
+ "changelog": {
+ "type": "boolean",
+ "description": "AI-enriched changelog entries",
+ "default": true
+ },
+ "enhance": {
+ "type": "boolean",
+ "description": "Spec metadata enhancement",
+ "default": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/packages/cli/src/config/validator.ts b/packages/cli/src/config/validator.ts
new file mode 100644
index 0000000..c152a43
--- /dev/null
+++ b/packages/cli/src/config/validator.ts
@@ -0,0 +1,58 @@
+import Ajv from 'ajv';
+import addFormats from 'ajv-formats';
+const AjvConstructor = Ajv.default ?? Ajv;
+const addFormatsFunc = addFormats.default ?? addFormats;
+import type { ContractualConfig } from '@contractual/types';
+import configSchema from './schema.json' with { type: 'json' };
+
+/**
+ * Validation error with path and message
+ */
+export interface ValidationError {
+ path: string;
+ message: string;
+}
+
+/**
+ * Result of config validation
+ */
+export interface ValidationResult {
+ valid: boolean;
+ errors: ValidationError[];
+}
+
+/**
+ * Validates a parsed config object against the JSON schema
+ */
+export function validateConfig(config: unknown): ValidationResult {
+ const ajv = new AjvConstructor({ allErrors: true, strict: false });
+ addFormatsFunc(ajv);
+
+ const validate = ajv.compile(configSchema);
+ const valid = validate(config);
+
+ if (valid) {
+ return { valid: true, errors: [] };
+ }
+
+ const errors: ValidationError[] = (validate.errors ?? []).map((err) => ({
+ path: err.instancePath || '/',
+ message: err.message ?? 'Unknown validation error',
+ }));
+
+ return { valid: false, errors };
+}
+
+/**
+ * Type guard to check if config is valid ContractualConfig
+ */
+export function isValidConfig(config: unknown): config is ContractualConfig {
+ return validateConfig(config).valid;
+}
+
+/**
+ * Format validation errors for display
+ */
+export function formatValidationErrors(errors: ValidationError[]): string {
+ return errors.map((err) => ` ${err.path}: ${err.message}`).join('\n');
+}
diff --git a/packages/cli/src/core/diff.ts b/packages/cli/src/core/diff.ts
new file mode 100644
index 0000000..2ff6b4e
--- /dev/null
+++ b/packages/cli/src/core/diff.ts
@@ -0,0 +1,128 @@
+/**
+ * Core diffing logic
+ *
+ * Shared module for running diffs across contracts.
+ * Used by `diff`, `breaking`, and `changeset` commands.
+ */
+
+import type { ResolvedConfig, ResolvedContract, DiffResult } from '@contractual/types';
+import { getDiffer } from '../governance/index.js';
+import { findContractualDir, getSnapshotPath } from '../utils/files.js';
+
+export interface DiffOptions {
+ /** Filter to specific contract names */
+ contracts?: string[];
+ /** Include contracts with no changes in results */
+ includeEmpty?: boolean;
+}
+
+export interface DiffContractsResult {
+ results: DiffResult[];
+ contractualDir: string;
+}
+
+/**
+ * Core diffing function. Runs the appropriate differ for each contract,
+ * comparing current spec against last versioned snapshot.
+ *
+ * Returns classified changes for all contracts.
+ * This is the primitive that `diff`, `breaking`, and `changeset` all use.
+ */
+export async function diffContracts(
+ config: ResolvedConfig,
+ options: DiffOptions = {}
+): Promise {
+ const contractualDir = findContractualDir(config.configDir);
+ if (!contractualDir) {
+ throw new Error('No .contractual directory found. Run `contractual init` first.');
+ }
+
+ // Filter contracts if specific ones requested
+ let contracts: ResolvedContract[] = config.contracts;
+ if (options.contracts && options.contracts.length > 0) {
+ contracts = config.contracts.filter((c) => options.contracts!.includes(c.name));
+
+ // Check for missing contracts
+ for (const name of options.contracts) {
+ if (!config.contracts.some((c) => c.name === name)) {
+ throw new Error(`Contract "${name}" not found in configuration.`);
+ }
+ }
+ }
+
+ const results: DiffResult[] = [];
+
+ for (const contract of contracts) {
+ const result = await diffSingleContract(contract, contractualDir);
+
+ // Include result if it has changes, or if includeEmpty is true
+ if (result.changes.length > 0 || options.includeEmpty) {
+ results.push(result);
+ }
+ }
+
+ return { results, contractualDir };
+}
+
+/**
+ * Diff a single contract against its snapshot
+ */
+async function diffSingleContract(
+ contract: ResolvedContract,
+ contractualDir: string
+): Promise {
+ // Get snapshot path
+ const snapshotPath = getSnapshotPath(contract.name, contractualDir);
+
+ // No snapshot = first version, no changes
+ if (!snapshotPath) {
+ return createEmptyResult(contract.name, 'first-version');
+ }
+
+ // Check if breaking detection is disabled
+ if (contract.breaking === false) {
+ return createEmptyResult(contract.name, 'disabled');
+ }
+
+ // Get the differ from the registry
+ const differ = getDiffer(contract.type, contract.breaking);
+
+ if (differ === null) {
+ // Disabled via config override
+ return createEmptyResult(contract.name, 'disabled');
+ }
+
+ if (!differ) {
+ // No differ registered for this type
+ return createEmptyResult(contract.name, 'no-differ');
+ }
+
+ // Run the differ: snapshot (old) vs current spec (new)
+ const diffResult = await differ(snapshotPath, contract.absolutePath);
+
+ // Override contract name to match config
+ return {
+ ...diffResult,
+ contract: contract.name,
+ };
+}
+
+/**
+ * Create an empty diff result
+ */
+function createEmptyResult(
+ contractName: string,
+ _reason: 'first-version' | 'disabled' | 'no-differ'
+): DiffResult {
+ return {
+ contract: contractName,
+ changes: [],
+ summary: {
+ breaking: 0,
+ nonBreaking: 0,
+ patch: 0,
+ unknown: 0,
+ },
+ suggestedBump: 'none',
+ };
+}
diff --git a/packages/cli/src/formatters/diff.ts b/packages/cli/src/formatters/diff.ts
new file mode 100644
index 0000000..ff1b495
--- /dev/null
+++ b/packages/cli/src/formatters/diff.ts
@@ -0,0 +1,164 @@
+/**
+ * Diff output formatters
+ *
+ * Format diff results for text and JSON output.
+ */
+
+import chalk from 'chalk';
+import type { DiffResult, Change, ChangeSeverity, DiffSummary } from '@contractual/types';
+
+export interface FormatOptions {
+ /** Show JSON Pointer paths for each change */
+ verbose?: boolean;
+}
+
+/**
+ * Format diff results as human-readable text
+ */
+export function formatDiffText(results: DiffResult[], options: FormatOptions = {}): void {
+ if (results.length === 0) {
+ console.log(chalk.dim('No contracts to diff.'));
+ return;
+ }
+
+ for (const result of results) {
+ formatContractResult(result, options);
+ }
+}
+
+/**
+ * Format a single contract's diff result
+ */
+function formatContractResult(result: DiffResult, options: FormatOptions): void {
+ if (result.changes.length === 0) {
+ console.log(`${chalk.cyan(result.contract)}: ${chalk.dim('no changes')}`);
+ console.log();
+ return;
+ }
+
+ // Build summary parts
+ const parts: string[] = [];
+ if (result.summary.breaking > 0) {
+ parts.push(`${result.summary.breaking} breaking`);
+ }
+ if (result.summary.nonBreaking > 0) {
+ parts.push(`${result.summary.nonBreaking} non-breaking`);
+ }
+ if (result.summary.patch > 0) {
+ parts.push(`${result.summary.patch} patch`);
+ }
+ if (result.summary.unknown > 0) {
+ parts.push(`${result.summary.unknown} unknown`);
+ }
+
+ // Color for suggested bump
+ const bumpColor =
+ result.suggestedBump === 'major'
+ ? chalk.red
+ : result.suggestedBump === 'minor'
+ ? chalk.yellow
+ : chalk.green;
+
+ // Header line
+ console.log(
+ `${chalk.cyan(result.contract)}: ${result.changes.length} change(s) (${parts.join(', ')}) β suggested bump: ${bumpColor(result.suggestedBump)}`
+ );
+ console.log();
+
+ // Each change
+ for (const change of result.changes) {
+ const label = formatSeverityLabel(change.severity);
+ console.log(` ${label} ${change.message}`);
+ if (options.verbose && change.path) {
+ console.log(`${' '.repeat(14)}path: ${chalk.dim(change.path)}`);
+ }
+ }
+ console.log();
+}
+
+/**
+ * Format severity as a colored, padded label
+ */
+function formatSeverityLabel(severity: ChangeSeverity): string {
+ switch (severity) {
+ case 'breaking':
+ return chalk.red.bold('BREAKING'.padEnd(12));
+ case 'non-breaking':
+ return chalk.yellow('non-breaking');
+ case 'patch':
+ return chalk.green('patch'.padEnd(12));
+ case 'unknown':
+ return chalk.gray('unknown'.padEnd(12));
+ default:
+ return chalk.gray(String(severity).padEnd(12));
+ }
+}
+
+/**
+ * Format diff results as JSON
+ *
+ * Output format:
+ * {
+ * "contracts": {
+ * "order": { "changes": [...], "summary": {...}, "suggestedBump": "minor" },
+ * "petstore": { "changes": [...], "summary": {...}, "suggestedBump": "none" }
+ * }
+ * }
+ */
+export function formatDiffJson(results: DiffResult[]): string {
+ const contracts: Record> = {};
+
+ for (const result of results) {
+ const { contract, ...rest } = result;
+ contracts[contract] = rest;
+ }
+
+ return JSON.stringify({ contracts }, null, 2);
+}
+
+/**
+ * Filter results by severity level
+ */
+export function filterBySeverity(results: DiffResult[], severity: string): DiffResult[] {
+ if (severity === 'all') {
+ return results;
+ }
+
+ return results.map((r) => {
+ const filteredChanges = r.changes.filter((c) => c.severity === severity);
+ return {
+ ...r,
+ changes: filteredChanges,
+ summary: recalculateSummary(filteredChanges),
+ suggestedBump: calculateSuggestedBump(filteredChanges),
+ };
+ });
+}
+
+/**
+ * Recalculate summary from filtered changes
+ */
+function recalculateSummary(changes: Change[]): DiffSummary {
+ return {
+ breaking: changes.filter((c) => c.severity === 'breaking').length,
+ nonBreaking: changes.filter((c) => c.severity === 'non-breaking').length,
+ patch: changes.filter((c) => c.severity === 'patch').length,
+ unknown: changes.filter((c) => c.severity === 'unknown').length,
+ };
+}
+
+/**
+ * Calculate suggested bump from changes
+ */
+function calculateSuggestedBump(changes: Change[]): 'major' | 'minor' | 'patch' | 'none' {
+ if (changes.some((c) => c.severity === 'breaking')) {
+ return 'major';
+ }
+ if (changes.some((c) => c.severity === 'non-breaking')) {
+ return 'minor';
+ }
+ if (changes.some((c) => c.severity === 'patch')) {
+ return 'patch';
+ }
+ return 'none';
+}
diff --git a/packages/cli/src/governance/index.ts b/packages/cli/src/governance/index.ts
new file mode 100644
index 0000000..7148303
--- /dev/null
+++ b/packages/cli/src/governance/index.ts
@@ -0,0 +1,31 @@
+/**
+ * Re-export governance engines from @contractual/governance
+ *
+ * This module re-exports the governance registry functions and auto-registers
+ * all built-in engines on import.
+ */
+
+// Import to trigger auto-registration of all engines
+import '@contractual/governance';
+
+// Re-export registry functions
+export {
+ registerLinter,
+ registerDiffer,
+ getLinter,
+ getDiffer,
+ hasLinter,
+ hasDiffer,
+ getRegisteredLinterTypes,
+ getRegisteredDifferTypes,
+} from '@contractual/governance';
+
+// Re-export individual engines for direct use
+export { lintOpenAPI, lintJsonSchema, diffOpenApi, diffJsonSchema } from '@contractual/governance';
+
+// Re-export runner utilities for custom commands
+export {
+ executeCustomCommand,
+ parseCustomLintOutput,
+ parseCustomDiffOutput,
+} from '@contractual/governance';
diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts
index d0d3bbd..cc6993d 100644
--- a/packages/cli/src/index.ts
+++ b/packages/cli/src/index.ts
@@ -1 +1,38 @@
-export * from './commands.js';
+// Public API for programmatic use
+export { loadConfig, ConfigError } from './config/index.js';
+export { registerLinter, registerDiffer, getLinter, getDiffer } from './governance/index.js';
+
+// Core diffing
+export { diffContracts } from './core/diff.js';
+export type { DiffOptions, DiffContractsResult } from './core/diff.js';
+
+// File utilities
+export {
+ findContractualDir,
+ getSnapshotPath,
+ copyToSnapshots,
+ CONTRACTUAL_DIR,
+} from './utils/files.js';
+
+// Re-export from @contractual/changesets
+export {
+ VersionManager,
+ PreReleaseManager,
+ createChangeset,
+ readChangesets,
+ aggregateBumps,
+ generateChangesetName,
+ extractContractChanges,
+ appendChangelog,
+ incrementVersion,
+ incrementVersionWithPreRelease,
+ VERSIONS_FILE,
+ SNAPSHOTS_DIR,
+ CHANGESETS_DIR,
+ PRE_RELEASE_FILE,
+ updateSpecVersion,
+} from '@contractual/changesets';
+export type { BumpOperationResult } from '@contractual/changesets';
+
+// Re-export types from @contractual/types
+export type * from '@contractual/types';
diff --git a/packages/cli/src/utils/exec.ts b/packages/cli/src/utils/exec.ts
new file mode 100644
index 0000000..8c0a540
--- /dev/null
+++ b/packages/cli/src/utils/exec.ts
@@ -0,0 +1,105 @@
+import { execSync, type ExecSyncOptions } from 'node:child_process';
+
+/**
+ * Result of executing a command
+ */
+export interface ExecResult {
+ /** Standard output */
+ stdout: string;
+ /** Standard error */
+ stderr: string;
+ /** Exit code */
+ exitCode: number;
+}
+
+/**
+ * Error shape from execSync when command fails
+ */
+interface ExecSyncError {
+ stdout?: Buffer | string;
+ stderr?: Buffer | string;
+ status?: number;
+}
+
+/**
+ * Type guard for execSync errors
+ */
+function isExecSyncError(err: unknown): err is ExecSyncError {
+ return (
+ typeof err === 'object' &&
+ err !== null &&
+ ('status' in err || 'stdout' in err || 'stderr' in err)
+ );
+}
+
+/**
+ * Substitute placeholders in a command string
+ */
+export function substitutePlaceholders(
+ command: string,
+ substitutions: Record
+): string {
+ let result = command;
+ for (const [key, value] of Object.entries(substitutions)) {
+ result = result.replace(new RegExp(`\\{${key}\\}`, 'g'), value);
+ }
+ return result;
+}
+
+/**
+ * Check if a string contains placeholders
+ */
+export function hasPlaceholders(command: string): boolean {
+ return /\{(spec|old|new)\}/.test(command);
+}
+
+/**
+ * Execute a command and return the result
+ */
+export function execCommand(
+ command: string,
+ substitutions: Record = {},
+ options: ExecSyncOptions = {}
+): ExecResult {
+ const resolvedCommand = substitutePlaceholders(command, substitutions);
+
+ try {
+ const stdout = execSync(resolvedCommand, {
+ encoding: 'utf-8',
+ stdio: ['pipe', 'pipe', 'pipe'],
+ ...options,
+ }) as string;
+ return { stdout, stderr: '', exitCode: 0 };
+ } catch (err: unknown) {
+ if (isExecSyncError(err)) {
+ const stdout = typeof err.stdout === 'string' ? err.stdout : (err.stdout?.toString() ?? '');
+ const stderr = typeof err.stderr === 'string' ? err.stderr : (err.stderr?.toString() ?? '');
+ return {
+ stdout,
+ stderr,
+ exitCode: err.status ?? 1,
+ };
+ }
+ // Unknown error type - return generic failure
+ return {
+ stdout: '',
+ stderr: err instanceof Error ? err.message : 'Unknown error',
+ exitCode: 1,
+ };
+ }
+}
+
+/**
+ * Execute a command and throw if it fails
+ */
+export function execCommandOrThrow(
+ command: string,
+ substitutions: Record = {},
+ options: ExecSyncOptions = {}
+): string {
+ const result = execCommand(command, substitutions, options);
+ if (result.exitCode !== 0) {
+ throw new Error(`Command failed with exit code ${result.exitCode}: ${result.stderr}`);
+ }
+ return result.stdout;
+}
diff --git a/packages/cli/src/utils/files.ts b/packages/cli/src/utils/files.ts
new file mode 100644
index 0000000..d73fd4f
--- /dev/null
+++ b/packages/cli/src/utils/files.ts
@@ -0,0 +1,160 @@
+import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync } from 'node:fs';
+import { dirname, extname, join, resolve } from 'node:path';
+import { parse as parseYaml } from 'yaml';
+import type { ContractType } from '@contractual/types';
+import { CHANGESETS_DIR, SNAPSHOTS_DIR, VERSIONS_FILE } from '@contractual/changesets';
+
+/**
+ * The .contractual directory name
+ */
+export const CONTRACTUAL_DIR = '.contractual';
+
+// Re-export constants from @contractual/changesets for backward compatibility
+export { CHANGESETS_DIR, SNAPSHOTS_DIR, VERSIONS_FILE };
+
+/**
+ * Find the .contractual directory starting from a given path
+ */
+export function findContractualDir(startDir: string = process.cwd()): string | null {
+ let currentDir = resolve(startDir);
+ const root = dirname(currentDir);
+
+ while (currentDir !== root) {
+ const contractualDir = join(currentDir, CONTRACTUAL_DIR);
+ if (existsSync(contractualDir)) {
+ return contractualDir;
+ }
+ const parentDir = dirname(currentDir);
+ if (parentDir === currentDir) break;
+ currentDir = parentDir;
+ }
+
+ // Check root directory too
+ const contractualDir = join(currentDir, CONTRACTUAL_DIR);
+ if (existsSync(contractualDir)) {
+ return contractualDir;
+ }
+
+ return null;
+}
+
+/**
+ * Ensure the .contractual directory structure exists
+ */
+export function ensureContractualDir(baseDir: string): string {
+ const contractualDir = join(baseDir, CONTRACTUAL_DIR);
+ const changesetsDir = join(contractualDir, CHANGESETS_DIR);
+ const snapshotsDir = join(contractualDir, SNAPSHOTS_DIR);
+
+ mkdirSync(changesetsDir, { recursive: true });
+ mkdirSync(snapshotsDir, { recursive: true });
+
+ // Create versions.json if it doesn't exist
+ const versionsPath = join(contractualDir, VERSIONS_FILE);
+ if (!existsSync(versionsPath)) {
+ writeFileSync(versionsPath, '{}', 'utf-8');
+ }
+
+ // Create .gitkeep files
+ const changesetsGitkeep = join(changesetsDir, '.gitkeep');
+ const snapshotsGitkeep = join(snapshotsDir, '.gitkeep');
+ if (!existsSync(changesetsGitkeep)) {
+ writeFileSync(changesetsGitkeep, '', 'utf-8');
+ }
+ if (!existsSync(snapshotsGitkeep)) {
+ writeFileSync(snapshotsGitkeep, '', 'utf-8');
+ }
+
+ return contractualDir;
+}
+
+/**
+ * Read and parse a spec file (YAML or JSON)
+ */
+export function readSpecFile(filePath: string): unknown {
+ const content = readFileSync(filePath, 'utf-8');
+ const ext = extname(filePath).toLowerCase();
+
+ if (ext === '.json') {
+ return JSON.parse(content);
+ }
+
+ // YAML (handles .yaml, .yml)
+ return parseYaml(content);
+}
+
+/**
+ * Detect spec type from file path and content
+ */
+export function detectSpecType(filePath: string): ContractType | null {
+ // Check extension patterns first
+ if (/\.openapi\.(ya?ml|json)$/i.test(filePath)) return 'openapi';
+ if (/\.asyncapi\.(ya?ml|json)$/i.test(filePath)) return 'asyncapi';
+ if (/\.odcs\.ya?ml$/i.test(filePath)) return 'odcs';
+ if (/\.schema\.json$/i.test(filePath)) return 'json-schema';
+
+ // Content sniffing
+ try {
+ const spec = readSpecFile(filePath) as Record;
+ if (!spec || typeof spec !== 'object') return null;
+
+ // OpenAPI detection
+ if ('openapi' in spec || 'swagger' in spec) return 'openapi';
+
+ // AsyncAPI detection
+ if ('asyncapi' in spec) return 'asyncapi';
+
+ // ODCS detection
+ if ('dataContractSpecification' in spec || spec.kind === 'DataContract') return 'odcs';
+
+ // JSON Schema detection
+ if (
+ ('$schema' in spec && String(spec.$schema).includes('json-schema')) ||
+ ('type' in spec && 'properties' in spec)
+ )
+ return 'json-schema';
+
+ return null;
+ } catch {
+ return null;
+ }
+}
+
+/**
+ * Get the file extension for a contract type
+ */
+export function getSpecExtension(filePath: string): string {
+ const ext = extname(filePath).toLowerCase();
+ return ext || '.yaml';
+}
+
+/**
+ * Copy a spec file to the snapshots directory
+ */
+export function copyToSnapshots(
+ specPath: string,
+ contractName: string,
+ contractualDir: string
+): string {
+ const ext = getSpecExtension(specPath);
+ const snapshotPath = join(contractualDir, SNAPSHOTS_DIR, `${contractName}${ext}`);
+ copyFileSync(specPath, snapshotPath);
+ return snapshotPath;
+}
+
+/**
+ * Get the snapshot path for a contract
+ */
+export function getSnapshotPath(contractName: string, contractualDir: string): string | null {
+ const snapshotsDir = join(contractualDir, SNAPSHOTS_DIR);
+ const extensions = ['.yaml', '.yml', '.json'];
+
+ for (const ext of extensions) {
+ const snapshotPath = join(snapshotsDir, `${contractName}${ext}`);
+ if (existsSync(snapshotPath)) {
+ return snapshotPath;
+ }
+ }
+
+ return null;
+}
diff --git a/packages/cli/src/utils/index.ts b/packages/cli/src/utils/index.ts
new file mode 100644
index 0000000..5741bd7
--- /dev/null
+++ b/packages/cli/src/utils/index.ts
@@ -0,0 +1,3 @@
+export * from './exec.js';
+export * from './files.js';
+export * from './output.js';
diff --git a/packages/cli/src/utils/output.ts b/packages/cli/src/utils/output.ts
new file mode 100644
index 0000000..8f23bbe
--- /dev/null
+++ b/packages/cli/src/utils/output.ts
@@ -0,0 +1,87 @@
+import chalk from 'chalk';
+
+/**
+ * Print a success message with green checkmark
+ */
+export function printSuccess(message: string): void {
+ console.log(chalk.green('β') + ' ' + message);
+}
+
+/**
+ * Print an error message with red X
+ */
+export function printError(message: string): void {
+ console.log(chalk.red('β') + ' ' + message);
+}
+
+/**
+ * Print a warning message with yellow warning symbol
+ */
+export function printWarning(message: string): void {
+ console.log(chalk.yellow('β ') + ' ' + message);
+}
+
+/**
+ * Print an info message with blue info symbol
+ */
+export function printInfo(message: string): void {
+ console.log(chalk.blue('βΉ') + ' ' + message);
+}
+
+/**
+ * Print a simple ASCII table
+ */
+export function printTable(headers: string[], rows: string[][]): void {
+ if (headers.length === 0) {
+ return;
+ }
+
+ // Calculate column widths
+ const columnWidths = headers.map((header, index) => {
+ const maxRowWidth = rows.reduce((max, row) => {
+ const cellLength = row[index]?.length ?? 0;
+ return Math.max(max, cellLength);
+ }, 0);
+ return Math.max(header.length, maxRowWidth);
+ });
+
+ // Create separator line
+ const separator = '+' + columnWidths.map((width) => '-'.repeat(width + 2)).join('+') + '+';
+
+ // Format a row
+ const formatRow = (cells: string[]): string => {
+ return (
+ '|' +
+ cells.map((cell, index) => ' ' + (cell ?? '').padEnd(columnWidths[index]) + ' ').join('|') +
+ '|'
+ );
+ };
+
+ // Print table
+ console.log(separator);
+ console.log(formatRow(headers));
+ console.log(separator);
+ for (const row of rows) {
+ console.log(formatRow(row));
+ }
+ console.log(separator);
+}
+
+/**
+ * Format severity level with appropriate color
+ */
+export function formatSeverity(
+ severity: 'breaking' | 'non-breaking' | 'patch' | 'unknown'
+): string {
+ switch (severity) {
+ case 'breaking':
+ return chalk.red.bold('BREAKING');
+ case 'non-breaking':
+ return chalk.yellow('NON-BREAKING');
+ case 'patch':
+ return chalk.green('PATCH');
+ case 'unknown':
+ default:
+ return chalk.gray('UNKNOWN');
+ }
+}
diff --git a/packages/cli/src/utils/prompts.ts b/packages/cli/src/utils/prompts.ts
new file mode 100644
index 0000000..5d135f7
--- /dev/null
+++ b/packages/cli/src/utils/prompts.ts
@@ -0,0 +1,160 @@
+import { select, input, confirm } from '@inquirer/prompts';
+
+/**
+ * Check if running in interactive mode (TTY available)
+ */
+export function isInteractive(): boolean {
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
+}
+
+/**
+ * Check if running in CI environment
+ */
+export function isCI(): boolean {
+ return (
+ process.env.CI === 'true' ||
+ process.env.CI === '1' ||
+ process.env.CONTINUOUS_INTEGRATION === 'true' ||
+ process.env.GITHUB_ACTIONS === 'true' ||
+ process.env.GITLAB_CI === 'true' ||
+ process.env.CIRCLECI === 'true'
+ );
+}
+
+/**
+ * Options for prompt functions
+ */
+export interface PromptOptions {
+ /** Skip prompts and use defaults (--yes flag) */
+ yes?: boolean;
+ /** Force interactive mode even in CI */
+ interactive?: boolean;
+}
+
+/**
+ * Determine if prompts should be shown
+ */
+export function shouldPrompt(options: PromptOptions): boolean {
+ if (options.yes) return false;
+ if (options.interactive) return true;
+ if (isCI()) return false;
+ return isInteractive();
+}
+
+/**
+ * Prompt for a selection from a list of choices
+ */
+export async function promptSelect(
+ message: string,
+ choices: Array<{ value: T; name: string; description?: string }>,
+ defaultValue: T,
+ options: PromptOptions = {}
+): Promise {
+ if (!shouldPrompt(options)) {
+ return defaultValue;
+ }
+
+ return select({
+ message,
+ choices: choices.map((c) => ({
+ value: c.value,
+ name: c.name,
+ description: c.description,
+ })),
+ default: defaultValue,
+ });
+}
+
+/**
+ * Prompt for text input
+ */
+export async function promptInput(
+ message: string,
+ defaultValue: string,
+ options: PromptOptions = {}
+): Promise {
+ if (!shouldPrompt(options)) {
+ return defaultValue;
+ }
+
+ return input({
+ message,
+ default: defaultValue,
+ });
+}
+
+/**
+ * Prompt for confirmation (yes/no)
+ */
+export async function promptConfirm(
+ message: string,
+ defaultValue: boolean,
+ options: PromptOptions = {}
+): Promise {
+ if (!shouldPrompt(options)) {
+ return defaultValue;
+ }
+
+ return confirm({
+ message,
+ default: defaultValue,
+ });
+}
+
+/**
+ * Prompt for version input with validation
+ */
+export async function promptVersion(
+ message: string,
+ defaultValue: string,
+ options: PromptOptions = {}
+): Promise {
+ if (!shouldPrompt(options)) {
+ return defaultValue;
+ }
+
+ const result = await input({
+ message,
+ default: defaultValue,
+ validate: (value) => {
+ const semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
+ if (semverRegex.test(value)) {
+ return true;
+ }
+ return 'Please enter a valid semver version (e.g., 0.0.0, 1.2.3-beta.1)';
+ },
+ });
+
+ return result;
+}
+
+/**
+ * Common version choices for init
+ */
+export const VERSION_CHOICES = [
+ { value: '0.0.0', name: '0.0.0', description: 'Start fresh (recommended for new projects)' },
+ { value: '1.0.0', name: '1.0.0', description: 'Production-ready' },
+ { value: 'custom', name: 'Custom', description: 'Enter a custom version' },
+] as const;
+
+/**
+ * Common versioning mode choices
+ */
+export const VERSIONING_MODE_CHOICES = [
+ {
+ value: 'independent',
+ name: 'Independent',
+ description: 'Each contract versioned separately',
+ },
+ { value: 'fixed', name: 'Fixed', description: 'All contracts share same version' },
+] as const;
+
+/**
+ * Contract type choices
+ */
+export const CONTRACT_TYPE_CHOICES = [
+ { value: 'openapi', name: 'OpenAPI', description: 'OpenAPI/Swagger specification' },
+ { value: 'asyncapi', name: 'AsyncAPI', description: 'AsyncAPI specification' },
+ { value: 'json-schema', name: 'JSON Schema', description: 'JSON Schema definition' },
+ { value: 'odcs', name: 'ODCS', description: 'Open Data Contract Standard' },
+] as const;
diff --git a/packages/cli/tsconfig.build.json b/packages/cli/tsconfig.build.json
index 5695712..ad568f0 100644
--- a/packages/cli/tsconfig.build.json
+++ b/packages/cli/tsconfig.build.json
@@ -3,16 +3,14 @@
"compilerOptions": {
"rootDir": "src",
"baseUrl": ".",
- "outDir": "dist",
- "esModuleInterop": true,
+ "outDir": "dist"
},
+ "include": ["src/**/*"],
"exclude": [
- "index.ts",
"dist",
"node_modules",
"test",
"**/*.spec.ts",
- "**/*.test.ts",
- "jest.config.ts"
+ "**/*.test.ts"
]
}
\ No newline at end of file
diff --git a/packages/contract/.DS_Store b/packages/contract/.DS_Store
deleted file mode 100644
index 2af1a89..0000000
Binary files a/packages/contract/.DS_Store and /dev/null differ
diff --git a/packages/contract/.gitignore b/packages/contract/.gitignore
deleted file mode 100644
index 1c849ee..0000000
--- a/packages/contract/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-contract/*.js
\ No newline at end of file
diff --git a/packages/contract/contract/index.d.ts b/packages/contract/contract/index.d.ts
deleted file mode 100644
index 817096b..0000000
--- a/packages/contract/contract/index.d.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import { z } from 'zod';
-export declare const CreatePetRequest: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
-}, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
-}, {
- name?: string;
- status?: "available" | "pending" | "sold";
-}>;
-export declare const CreatePetResponse: z.ZodObject<{
- id: z.ZodNumber;
-}, "strip", z.ZodTypeAny, {
- id?: number;
-}, {
- id?: number;
-}>;
-export declare const UpdatePetRequest: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
-}, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
-}, {
- name?: string;
- status?: "available" | "pending" | "sold";
-}>;
-export declare const GetPetResponse: z.ZodObject<{
- id: z.ZodNumber;
- name: z.ZodString;
- status: z.ZodEnum<["available", "pending", "sold"]>;
-}, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
-}, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
-}>;
-export declare const ApiContract: {
- addPet: {
- method: "POST";
- path: string;
- description: string;
- body: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }>;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- }, "strip", z.ZodTypeAny, {
- id?: number;
- }, {
- id?: number;
- }>;
- };
- };
- updatePet: {
- method: "PUT";
- path: string;
- description: string;
- body: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }>;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- name: z.ZodString;
- status: z.ZodEnum<["available", "pending", "sold"]>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }>;
- };
- };
- getPetById: {
- method: "GET";
- path: string;
- description: string;
- pathParams: z.ZodObject<{
- petId: z.ZodNumber;
- }, "strip", z.ZodTypeAny, {
- petId?: number;
- }, {
- petId?: number;
- }>;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- name: z.ZodString;
- status: z.ZodEnum<["available", "pending", "sold"]>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }>;
- };
- };
-};
-export declare const ApiOperations: {
- 'add pet': "addPet";
- 'update pet': "updatePet";
- 'get pet by id': "getPetById";
-};
-export declare const contract: {
- addPet: {
- description: string;
- body: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }>;
- method: "POST";
- path: string;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- }, "strip", z.ZodTypeAny, {
- id?: number;
- }, {
- id?: number;
- }>;
- };
- };
- updatePet: {
- description: string;
- body: z.ZodObject<{
- name: z.ZodString;
- status: z.ZodOptional>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- }>;
- method: "PUT";
- path: string;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- name: z.ZodString;
- status: z.ZodEnum<["available", "pending", "sold"]>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }>;
- };
- };
- getPetById: {
- description: string;
- pathParams: z.ZodObject<{
- petId: z.ZodNumber;
- }, "strip", z.ZodTypeAny, {
- petId?: number;
- }, {
- petId?: number;
- }>;
- method: "GET";
- path: string;
- responses: {
- 200: z.ZodObject<{
- id: z.ZodNumber;
- name: z.ZodString;
- status: z.ZodEnum<["available", "pending", "sold"]>;
- }, "strip", z.ZodTypeAny, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }, {
- name?: string;
- status?: "available" | "pending" | "sold";
- id?: number;
- }>;
- };
- };
-};
diff --git a/packages/contract/package.json b/packages/contract/package.json
deleted file mode 100644
index 572bb6c..0000000
--- a/packages/contract/package.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "name": "@contractual/contract",
- "private": false,
- "version": "0.0.0",
- "license": "MIT",
- "type": "module",
- "exports": {
- "./contract": {
- "import": "./contract/index.js",
- "require": "./contract/index.js"
- }
- },
- "typings": "contract/index.d.ts",
- "repository": {
- "type": "git",
- "url": "https://github.com/contractual-dev/contractual.git",
- "directory": "packages/contract"
- },
- "homepage": "https://contractual.dev",
- "bugs": {
- "url": "https://github.com/contractual-dev/contractual/issues"
- },
- "contributors": [
- {
- "name": "Omer Morad",
- "email": "omer.moradd@gmail.com"
- }
- ],
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/contractual-dev"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/contractual-dev"
- }
- ],
- "engines": {
- "node": ">=18.12.0"
- },
- "scripts": {
- "prebuild": "pnpm rimraf dist",
- "build": "exit 0",
- "build:watch": "tsc -p tsconfig.build.json --watch",
- "test": "vitest run",
- "lint": "exit 0"
- },
- "files": [
- "contract",
- "dist",
- "README.md"
- ],
- "dependencies": {
- "@ts-rest/core": "^3.51.0",
- "axios": "^1.7.9",
- "zod": "^3.24.1"
- },
- "publishConfig": {
- "access": "public",
- "provenance": true
- }
-}
diff --git a/packages/contract/tsconfig.build.json b/packages/contract/tsconfig.build.json
deleted file mode 100644
index 91d6c8b..0000000
--- a/packages/contract/tsconfig.build.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "extends": "../../tsconfig.build.json",
- "compilerOptions": {
- "rootDir": "contract",
- "baseUrl": ".",
- "outDir": "dist",
- "esModuleInterop": true},
- "exclude": [
- "index.ts",
- "contract",
- "dist",
- "node_modules",
- "test",
- "**/*.spec.ts",
- "jest.config.ts"
- ]
-}
\ No newline at end of file
diff --git a/packages/contract/tsconfig.json b/packages/contract/tsconfig.json
deleted file mode 100644
index 7460ef4..0000000
--- a/packages/contract/tsconfig.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../tsconfig.json"
-}
\ No newline at end of file
diff --git a/packages/differs.core/package.json b/packages/differs.core/package.json
new file mode 100644
index 0000000..af6d148
--- /dev/null
+++ b/packages/differs.core/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@contractual/differs.core",
+ "version": "0.1.0-dev.5",
+ "description": "Core schema diffing primitives β walker, classifiers, ref-resolver β shared across Contractual differs",
+ "license": "MIT",
+ "type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/differs.core"
+ },
+ "homepage": "https://github.com/contractual-dev/contractual/tree/main/packages/differs.core",
+ "bugs": {
+ "url": "https://github.com/contractual-dev/contractual/issues"
+ },
+ "keywords": [
+ "json-schema",
+ "diff",
+ "breaking-changes",
+ "semver",
+ "schema",
+ "api",
+ "compatibility"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "rimraf dist",
+ "build": "tsc -p tsconfig.build.json",
+ "build:watch": "tsc -p tsconfig.build.json --watch"
+ },
+ "files": [
+ "dist",
+ "README.md"
+ ],
+ "dependencies": {
+ "@contractual/types": "workspace:*"
+ },
+ "devDependencies": {
+ "rimraf": "^5.0.5"
+ },
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/differs.core/src/assemble.ts b/packages/differs.core/src/assemble.ts
new file mode 100644
index 0000000..8b113df
--- /dev/null
+++ b/packages/differs.core/src/assemble.ts
@@ -0,0 +1,59 @@
+/**
+ * Result assembly β classify, format, summarize, and compute suggestedBump
+ */
+
+import type { RawChange, Change, ChangeSeverity, DiffResult } from '@contractual/types';
+import { classify, classifyPropertyAdded } from './classifiers.js';
+import { formatChangeMessage } from './format.js';
+
+export interface AssembleOptions {
+ contract?: string;
+ classifyFn?: (change: RawChange, newSchema: unknown) => ChangeSeverity;
+}
+
+export function assembleResult(
+ rawChanges: RawChange[],
+ resolvedNewSchema: unknown,
+ options?: AssembleOptions
+): DiffResult {
+ const classifyChange = options?.classifyFn ?? defaultClassify;
+
+ const changes: Change[] = rawChanges.map((raw) => ({
+ path: raw.path,
+ severity: classifyChange(raw, resolvedNewSchema),
+ category: raw.type,
+ message: formatChangeMessage(raw),
+ oldValue: raw.oldValue,
+ newValue: raw.newValue,
+ }));
+
+ const summary = {
+ breaking: changes.filter((c) => c.severity === 'breaking').length,
+ nonBreaking: changes.filter((c) => c.severity === 'non-breaking').length,
+ patch: changes.filter((c) => c.severity === 'patch').length,
+ unknown: changes.filter((c) => c.severity === 'unknown').length,
+ };
+
+ const suggestedBump =
+ summary.breaking > 0
+ ? 'major'
+ : summary.nonBreaking > 0
+ ? 'minor'
+ : summary.patch > 0
+ ? 'patch'
+ : 'none';
+
+ return {
+ contract: options?.contract ?? '',
+ changes,
+ summary,
+ suggestedBump,
+ };
+}
+
+function defaultClassify(change: RawChange, newSchema: unknown): ChangeSeverity {
+ if (change.type === 'property-added') {
+ return classifyPropertyAdded(change, newSchema);
+ }
+ return classify(change);
+}
diff --git a/packages/differs.core/src/classifiers.ts b/packages/differs.core/src/classifiers.ts
new file mode 100644
index 0000000..59b3930
--- /dev/null
+++ b/packages/differs.core/src/classifiers.ts
@@ -0,0 +1,417 @@
+/**
+ * JSON Schema Change Classifiers
+ *
+ * Classifies raw structural changes into severity levels for semantic versioning.
+ * Follows API compatibility principles where breaking changes require major bumps,
+ * additive changes require minor bumps, and metadata changes are patches.
+ */
+
+import type { RawChange, ChangeType, ChangeSeverity } from '@contractual/types';
+
+/**
+ * Change types that are always breaking (require major version bump)
+ *
+ * These changes can break existing consumers:
+ * - Removing properties removes data they may depend on
+ * - Adding required fields forces consumers to provide new data
+ * - Type changes can break parsing/validation
+ * - Enum removals can invalidate existing data
+ * - Tightened constraints can reject previously valid data
+ * - Composition option additions can change validation semantics
+ *
+ * Aligned with Strands API classification rules.
+ */
+const BREAKING_CHANGES: ReadonlySet = new Set([
+ 'property-removed',
+ 'required-added',
+ 'type-changed',
+ 'type-narrowed',
+ 'enum-value-removed',
+ 'enum-added',
+ 'constraint-tightened',
+ 'additional-properties-denied',
+ 'items-changed',
+ 'min-items-increased',
+ 'max-items-decreased',
+ 'ref-target-changed',
+ 'dependent-required-added',
+ // Composition breaking changes (per Strands API)
+ 'anyof-option-added',
+ 'oneof-option-added',
+ 'allof-member-added',
+ 'not-schema-changed',
+ // OpenAPI structural breaking changes
+ 'path-removed',
+ 'operation-removed',
+ 'parameter-required-added',
+ 'parameter-removed',
+ 'parameter-required-changed',
+ 'request-body-added',
+ 'response-removed',
+ 'security-changed',
+]);
+
+/**
+ * Change types that are non-breaking (require minor version bump)
+ *
+ * These changes are backward compatible additions/relaxations:
+ * - Adding optional properties extends the schema without breaking
+ * - Removing required constraints makes the schema more permissive
+ * - Type widening accepts more values
+ * - Loosened constraints accept more values
+ * - Composition option removals make schema less restrictive
+ *
+ * Aligned with Strands API classification rules.
+ */
+const NON_BREAKING_CHANGES: ReadonlySet = new Set([
+ 'property-added',
+ 'required-removed',
+ 'type-widened',
+ 'enum-value-added',
+ 'enum-removed',
+ 'constraint-loosened',
+ 'additional-properties-allowed',
+ 'additional-properties-changed',
+ 'dependent-required-removed',
+ // Composition non-breaking changes (per Strands API)
+ 'anyof-option-removed',
+ 'oneof-option-removed',
+ 'allof-member-removed',
+ // OpenAPI structural non-breaking changes
+ 'parameter-added',
+ 'path-added',
+ 'operation-added',
+ 'request-body-removed',
+ 'response-added',
+ 'server-changed',
+]);
+
+/**
+ * Change types that are patches (documentation/metadata only)
+ *
+ * These changes don't affect validation behavior:
+ * - Description changes are documentation only
+ * - Title changes are display metadata
+ * - Default/example changes don't affect validation
+ * - Format is an annotation (per Strands API) - doesn't affect validation
+ * - Annotation keywords (deprecated, readOnly, writeOnly)
+ * - Content keywords (contentEncoding, contentMediaType, contentSchema)
+ *
+ * Aligned with Strands API classification rules.
+ */
+const PATCH_CHANGES: ReadonlySet = new Set([
+ // Metadata changes
+ 'description-changed',
+ 'title-changed',
+ 'default-changed',
+ 'examples-changed',
+ // Format is annotation (patch per Strands API)
+ 'format-added',
+ 'format-removed',
+ 'format-changed',
+ // Annotation keywords (Draft 2019-09+)
+ 'deprecated-changed',
+ 'read-only-changed',
+ 'write-only-changed',
+ // Content keywords
+ 'content-encoding-changed',
+ 'content-media-type-changed',
+ 'content-schema-changed',
+]);
+
+/**
+ * Change types that require manual review
+ *
+ * These changes are too complex to classify automatically:
+ * - Generic composition changes require semantic analysis
+ * - Complex keywords (propertyNames, dependentSchemas, unevaluated*)
+ * - Conditional schema changes (if/then/else)
+ * - Unknown changes need human evaluation
+ *
+ * Aligned with Strands API classification rules.
+ */
+const UNKNOWN_CHANGES: ReadonlySet = new Set([
+ // Complex object keywords
+ 'property-names-changed',
+ 'dependent-schemas-changed',
+ 'unevaluated-properties-changed',
+ // Complex array keywords
+ 'unevaluated-items-changed',
+ 'min-contains-changed',
+ 'max-contains-changed',
+ // Conditional schema
+ 'if-then-else-changed',
+ // Legacy/generic composition
+ 'composition-changed',
+ // OpenAPI context-dependent (schema-level changes handled by walker)
+ 'parameter-schema-changed',
+ 'response-schema-changed',
+ // Catch-all
+ 'unknown-change',
+]);
+
+/**
+ * Export classification sets for external analysis
+ */
+export const CLASSIFICATION_SETS = {
+ breaking: BREAKING_CHANGES,
+ nonBreaking: NON_BREAKING_CHANGES,
+ patch: PATCH_CHANGES,
+ unknown: UNKNOWN_CHANGES,
+} as const;
+
+/**
+ * Classify a raw change into a severity level
+ *
+ * Uses the Strands API classification rules where:
+ * - Breaking changes require major version bump
+ * - Non-breaking changes require minor version bump
+ * - Patch changes are metadata/annotation only
+ * - Unknown changes require manual review
+ *
+ * @param change - The raw change to classify
+ * @returns The severity classification
+ *
+ * @example
+ * ```typescript
+ * const change: RawChange = {
+ * path: '/properties/name',
+ * type: 'property-removed',
+ * oldValue: { type: 'string' },
+ * };
+ * const severity = classify(change);
+ * // severity === 'breaking'
+ * ```
+ */
+export function classify(change: RawChange): ChangeSeverity {
+ const { type } = change;
+
+ // Check each category in order of specificity
+ if (BREAKING_CHANGES.has(type)) {
+ return 'breaking';
+ }
+
+ if (NON_BREAKING_CHANGES.has(type)) {
+ return 'non-breaking';
+ }
+
+ if (PATCH_CHANGES.has(type)) {
+ return 'patch';
+ }
+
+ if (UNKNOWN_CHANGES.has(type)) {
+ return 'unknown';
+ }
+
+ // Defensive: any unhandled type is unknown
+ return 'unknown';
+}
+
+/**
+ * Classify a property-added change with schema context
+ *
+ * Property additions are breaking if the property is required,
+ * otherwise they are non-breaking (additive).
+ *
+ * @param change - The property-added change
+ * @param newSchema - The new schema for context (to check required array)
+ * @returns The severity classification
+ *
+ * @example
+ * ```typescript
+ * const change: RawChange = {
+ * path: '/properties/email',
+ * type: 'property-added',
+ * newValue: { type: 'string', format: 'email' },
+ * };
+ *
+ * const schema = {
+ * type: 'object',
+ * properties: { email: { type: 'string', format: 'email' } },
+ * required: ['email'], // email is required!
+ * };
+ *
+ * const severity = classifyPropertyAdded(change, schema);
+ * // severity === 'breaking' (because email is in required[])
+ * ```
+ */
+export function classifyPropertyAdded(change: RawChange, newSchema: unknown): ChangeSeverity {
+ // Validate change type
+ if (change.type !== 'property-added') {
+ return classify(change);
+ }
+
+ // Extract property name from path
+ const propertyName = extractPropertyName(change.path);
+ if (!propertyName) {
+ // Cannot determine property name, fall back to non-breaking
+ return 'non-breaking';
+ }
+
+ // Find the parent schema containing this property
+ const parentSchema = findParentSchema(change.path, newSchema);
+ if (!parentSchema) {
+ // Cannot find parent schema, fall back to non-breaking
+ return 'non-breaking';
+ }
+
+ // Check if property is in the required array
+ const required = getRequiredArray(parentSchema);
+ if (required.includes(propertyName)) {
+ // Adding a required property is breaking
+ return 'breaking';
+ }
+
+ // Adding an optional property is non-breaking
+ return 'non-breaking';
+}
+
+/**
+ * Extract the property name from a JSON Pointer path
+ *
+ * @param path - JSON Pointer path (e.g., '/properties/name' or '/properties/user/properties/email')
+ * @returns The property name or null if not found
+ */
+function extractPropertyName(path: string): string | null {
+ // Match the last /properties/NAME segment
+ const match = path.match(/\/properties\/([^/]+)$/);
+ if (match?.[1] !== undefined) {
+ return decodeJsonPointerSegment(match[1]);
+ }
+
+ return null;
+}
+
+/**
+ * Decode a JSON Pointer segment (handles ~0 and ~1 escapes)
+ *
+ * @param segment - The encoded segment
+ * @returns The decoded segment
+ */
+function decodeJsonPointerSegment(segment: string): string {
+ return segment.replace(/~1/g, '/').replace(/~0/g, '~');
+}
+
+/**
+ * Find the parent schema containing a property
+ *
+ * @param path - JSON Pointer path to the property
+ * @param schema - The root schema
+ * @returns The parent schema or null if not found
+ */
+function findParentSchema(path: string, schema: unknown): unknown {
+ if (!isObject(schema)) {
+ return null;
+ }
+
+ // Remove the last segment to get parent path
+ // e.g., '/properties/name' -> '' (root)
+ // e.g., '/properties/user/properties/email' -> '/properties/user'
+ const segments = path.split('/').filter(Boolean);
+
+ // We need to navigate to the schema containing /properties/NAME
+ // So we remove 'properties' and 'NAME' from the end
+ if (segments.length < 2) {
+ // Path is too short, parent is root
+ return schema;
+ }
+
+ // Remove 'NAME' and 'properties' from the end
+ const parentSegments = segments.slice(0, -2);
+
+ // Navigate to parent
+ let current: unknown = schema;
+ for (const segment of parentSegments) {
+ if (!isObject(current)) {
+ return null;
+ }
+ const decoded = decodeJsonPointerSegment(segment);
+ current = (current as Record)[decoded];
+ }
+
+ return current;
+}
+
+/**
+ * Get the required array from a schema object
+ *
+ * @param schema - The schema object
+ * @returns Array of required property names
+ */
+function getRequiredArray(schema: unknown): string[] {
+ if (!isObject(schema)) {
+ return [];
+ }
+
+ const obj = schema as Record;
+ const required = obj['required'];
+
+ if (!Array.isArray(required)) {
+ return [];
+ }
+
+ return required.filter((item): item is string => typeof item === 'string');
+}
+
+/**
+ * Type guard for objects
+ */
+function isObject(value: unknown): value is Record {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
+/**
+ * Batch classify multiple changes
+ *
+ * @param changes - Array of raw changes
+ * @param newSchema - Optional schema for context-aware classification
+ * @returns Map of change to severity
+ */
+export function classifyAll(
+ changes: readonly RawChange[],
+ newSchema?: unknown
+): Map {
+ const results = new Map();
+
+ for (const change of changes) {
+ if (change.type === 'property-added' && newSchema !== undefined) {
+ results.set(change, classifyPropertyAdded(change, newSchema));
+ } else {
+ results.set(change, classify(change));
+ }
+ }
+
+ return results;
+}
+
+/**
+ * Get a human-readable message for a classified change
+ *
+ * @param change - The raw change
+ * @param severity - The classified severity
+ * @returns Human-readable description
+ */
+export function getChangeMessage(change: RawChange, severity: ChangeSeverity): string {
+ const severityLabel =
+ severity === 'breaking'
+ ? 'BREAKING'
+ : severity === 'non-breaking'
+ ? 'Non-breaking'
+ : severity === 'patch'
+ ? 'Patch'
+ : 'Unknown';
+
+ const typeLabel = formatChangeType(change.type);
+
+ return `[${severityLabel}] ${typeLabel} at ${change.path}`;
+}
+
+/**
+ * Format a change type into a human-readable label
+ */
+function formatChangeType(type: ChangeType): string {
+ return type
+ .split('-')
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ');
+}
diff --git a/packages/differs.core/src/format.ts b/packages/differs.core/src/format.ts
new file mode 100644
index 0000000..156896e
--- /dev/null
+++ b/packages/differs.core/src/format.ts
@@ -0,0 +1,237 @@
+/**
+ * Human-readable message formatting for raw changes
+ */
+
+import type { RawChange } from '@contractual/types';
+
+/**
+ * Format a human-readable message for a change
+ *
+ * @param change - The raw change to format
+ * @returns Human-readable message describing the change
+ */
+export function formatChangeMessage(change: RawChange): string {
+ const pathDisplay = decodeJsonPointer(change.path || '/');
+
+ switch (change.type) {
+ case 'property-added':
+ return `Property added at ${pathDisplay}`;
+
+ case 'property-removed':
+ return `Property removed at ${pathDisplay}`;
+
+ case 'required-added':
+ return `Field "${formatRequiredFieldName(change.newValue)}" made required at ${pathDisplay}`;
+
+ case 'required-removed':
+ return `Field "${formatRequiredFieldName(change.oldValue)}" made optional at ${pathDisplay}`;
+
+ case 'type-changed':
+ return `Type changed from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'type-narrowed':
+ return `Type narrowed from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'type-widened':
+ return `Type widened from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'enum-value-added':
+ return `Enum value ${formatValue(change.newValue)} added at ${pathDisplay}`;
+
+ case 'enum-value-removed':
+ return `Enum value ${formatValue(change.oldValue)} removed at ${pathDisplay}`;
+
+ case 'enum-added':
+ return `Enum constraint added at ${pathDisplay}`;
+
+ case 'enum-removed':
+ return `Enum constraint removed at ${pathDisplay}`;
+
+ case 'constraint-tightened':
+ return formatConstraintMessage(change, 'tightened', pathDisplay);
+
+ case 'constraint-loosened':
+ return formatConstraintMessage(change, 'loosened', pathDisplay);
+
+ case 'format-added':
+ return `Format "${change.newValue}" added at ${pathDisplay}`;
+
+ case 'format-removed':
+ return `Format "${change.oldValue}" removed at ${pathDisplay}`;
+
+ case 'format-changed':
+ return `Format changed from "${change.oldValue}" to "${change.newValue}" at ${pathDisplay}`;
+
+ case 'additional-properties-denied':
+ return `Additional properties denied at ${pathDisplay}`;
+
+ case 'additional-properties-allowed':
+ return `Additional properties allowed at ${pathDisplay}`;
+
+ case 'additional-properties-changed':
+ return `Additional properties schema changed at ${pathDisplay}`;
+
+ case 'items-changed':
+ return `Array items schema changed at ${pathDisplay}`;
+
+ case 'min-items-increased':
+ return `Minimum items increased from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'max-items-decreased':
+ return `Maximum items decreased from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'composition-changed':
+ return `Composition (allOf/anyOf/oneOf) changed at ${pathDisplay}`;
+
+ case 'ref-target-changed':
+ return `Reference target changed at ${pathDisplay}`;
+
+ case 'description-changed':
+ return `Description changed at ${pathDisplay}`;
+
+ case 'title-changed':
+ return `Title changed at ${pathDisplay}`;
+
+ case 'default-changed':
+ return `Default value changed at ${pathDisplay}`;
+
+ case 'examples-changed':
+ return `Examples changed at ${pathDisplay}`;
+
+ case 'deprecated-changed':
+ return change.newValue
+ ? `Deprecated at ${pathDisplay}`
+ : `No longer deprecated at ${pathDisplay}`;
+
+ case 'read-only-changed':
+ return `readOnly changed at ${pathDisplay}`;
+
+ case 'write-only-changed':
+ return `writeOnly changed at ${pathDisplay}`;
+
+ // OpenAPI structural changes
+ case 'path-added':
+ return `New path added: ${change.newValue ?? pathDisplay}`;
+
+ case 'path-removed':
+ return `Path removed: ${change.oldValue ?? pathDisplay}`;
+
+ case 'operation-added':
+ return `New operation added: ${change.newValue ?? pathDisplay}`;
+
+ case 'operation-removed':
+ return `Operation removed: ${change.oldValue ?? pathDisplay}`;
+
+ case 'parameter-added':
+ return `Optional parameter added at ${pathDisplay}`;
+
+ case 'parameter-required-added':
+ return `Required parameter added at ${pathDisplay}`;
+
+ case 'parameter-removed':
+ return `Parameter removed at ${pathDisplay}`;
+
+ case 'parameter-required-changed':
+ return `Parameter required changed from ${formatValue(change.oldValue)} to ${formatValue(change.newValue)} at ${pathDisplay}`;
+
+ case 'parameter-schema-changed':
+ return `Parameter schema changed at ${pathDisplay}`;
+
+ case 'request-body-added':
+ return `Request body added at ${pathDisplay}`;
+
+ case 'request-body-removed':
+ return `Request body removed at ${pathDisplay}`;
+
+ case 'response-added':
+ return `Response ${formatValue(change.newValue)} added at ${pathDisplay}`;
+
+ case 'response-removed':
+ return `Response ${formatValue(change.oldValue)} removed at ${pathDisplay}`;
+
+ case 'response-schema-changed':
+ return `Response schema changed at ${pathDisplay}`;
+
+ case 'security-changed':
+ return `Security changed at ${pathDisplay}`;
+
+ case 'server-changed':
+ return `Server changed at ${pathDisplay}`;
+
+ case 'unknown-change':
+ default:
+ return `Unknown change at ${pathDisplay}`;
+ }
+}
+
+/**
+ * Decode a JSON Pointer path for human-readable display (RFC 6901)
+ * ~1 β /
+ * ~0 β ~
+ */
+function decodeJsonPointer(path: string): string {
+ return path.replace(/~1/g, '/').replace(/~0/g, '~');
+}
+
+/**
+ * Format a value for display in messages
+ */
+function formatValue(value: unknown): string {
+ if (value === undefined) {
+ return 'undefined';
+ }
+ if (value === null) {
+ return 'null';
+ }
+ if (typeof value === 'string') {
+ return `"${value}"`;
+ }
+ if (Array.isArray(value)) {
+ return JSON.stringify(value);
+ }
+ if (typeof value === 'object') {
+ return JSON.stringify(value);
+ }
+ return String(value);
+}
+
+/**
+ * Format required field name from change value
+ */
+function formatRequiredFieldName(value: unknown): string {
+ if (typeof value === 'string') {
+ return value;
+ }
+ return String(value);
+}
+
+/**
+ * Format constraint change message
+ */
+function formatConstraintMessage(
+ change: RawChange,
+ direction: 'tightened' | 'loosened',
+ pathDisplay: string
+): string {
+ const constraintName = extractConstraintName(change.path);
+ const oldVal = change.oldValue !== undefined ? formatValue(change.oldValue) : 'none';
+ const newVal = change.newValue !== undefined ? formatValue(change.newValue) : 'none';
+
+ if (constraintName) {
+ return `Constraint "${constraintName}" ${direction} from ${oldVal} to ${newVal} at ${pathDisplay}`;
+ }
+
+ return `Constraint ${direction} from ${oldVal} to ${newVal} at ${pathDisplay}`;
+}
+
+/**
+ * Extract constraint name from path
+ */
+function extractConstraintName(path: string): string | null {
+ const segments = path.split('/');
+ const lastSegment = segments[segments.length - 1];
+ if (lastSegment && lastSegment !== '') {
+ return lastSegment;
+ }
+ return null;
+}
diff --git a/packages/differs.core/src/index.ts b/packages/differs.core/src/index.ts
new file mode 100644
index 0000000..bbb5561
--- /dev/null
+++ b/packages/differs.core/src/index.ts
@@ -0,0 +1,50 @@
+// Core walker
+export { walk } from './walker.js';
+
+// Classification
+export { classify, classifyPropertyAdded, classifyAll, CLASSIFICATION_SETS } from './classifiers.js';
+
+// Ref resolution
+export { resolveRefs, hasUnresolvedRefs, extractRefs, validateRefs, type ResolveResult } from './ref-resolver.js';
+
+// Message formatting
+export { formatChangeMessage } from './format.js';
+
+// Result assembly
+export { assembleResult, type AssembleOptions } from './assemble.js';
+
+// Schema types and utilities
+export type {
+ ResolvedSchema,
+ JSONSchemaType,
+ NormalizedType,
+ ConstraintKey,
+ ConstraintDirection,
+ ConstraintMeta,
+ CompositionKeyword,
+ MetadataKey,
+ AnnotationKey,
+ ContentKey,
+ WalkerContext,
+} from './types.js';
+
+export {
+ isSchemaObject,
+ isSchemaArray,
+ normalizeType,
+ arraysEqual,
+ deepEqual,
+ escapeJsonPointer,
+ joinPath,
+ CONSTRAINT_KEYS,
+ CONSTRAINT_DIRECTION,
+ COMPOSITION_KEYWORDS,
+ METADATA_KEYS,
+ ANNOTATION_KEYS,
+ CONTENT_KEYS,
+ DEFAULT_MAX_DEPTH,
+} from './types.js';
+
+// Re-export governance types from @contractual/types for convenience
+export type { ChangeType, ChangeSeverity, RawChange, Change, DiffResult, DiffSummary, SuggestedBump } from '@contractual/types';
+export { CHANGE_TYPE_SEVERITY } from '@contractual/types';
diff --git a/packages/differs.core/src/ref-resolver.ts b/packages/differs.core/src/ref-resolver.ts
new file mode 100644
index 0000000..c125601
--- /dev/null
+++ b/packages/differs.core/src/ref-resolver.ts
@@ -0,0 +1,435 @@
+/**
+ * JSON Schema $ref Resolver
+ *
+ * Resolves all $ref pointers in a JSON Schema, producing a self-contained schema.
+ * Handles internal references ($defs, definitions) and detects circular references.
+ *
+ * This resolver operates on in-memory schema objects and does not fetch external URLs.
+ * External references are flagged as warnings.
+ */
+
+/**
+ * Result of resolving references in a schema
+ */
+export interface ResolveResult {
+ /** The resolved schema with $refs replaced */
+ readonly schema: unknown;
+ /** Warnings encountered during resolution (circular refs, external refs, etc.) */
+ readonly warnings: string[];
+}
+
+/**
+ * Internal context for tracking resolution state
+ */
+interface ResolveContext {
+ /** The root schema for resolving internal references */
+ readonly root: unknown;
+ /** Accumulated warnings */
+ readonly warnings: string[];
+ /** Set of $ref paths currently being resolved (for circular detection) */
+ readonly resolving: Set;
+ /** Cache of already resolved $refs to their values */
+ readonly cache: Map;
+ /** Current JSON Pointer path (for error messages) */
+ currentPath: string;
+}
+
+/**
+ * Resolve all $ref pointers in a JSON Schema
+ *
+ * Creates a self-contained schema by inlining all internal references.
+ * Does not modify the original schema.
+ *
+ * @param schema - The JSON Schema to resolve
+ * @returns The resolved schema and any warnings
+ *
+ * @example
+ * ```typescript
+ * const schema = {
+ * type: 'object',
+ * properties: {
+ * user: { $ref: '#/$defs/User' }
+ * },
+ * $defs: {
+ * User: { type: 'object', properties: { name: { type: 'string' } } }
+ * }
+ * };
+ *
+ * const result = resolveRefs(schema);
+ * // result.schema.properties.user === { type: 'object', properties: { name: { type: 'string' } } }
+ * // result.warnings === []
+ * ```
+ */
+export function resolveRefs(schema: unknown): ResolveResult {
+ const context = {
+ root: schema,
+ warnings: [],
+ resolving: new Set(),
+ cache: new Map(),
+ currentPath: '',
+ } satisfies ResolveContext;
+
+ const resolved = resolveNode(schema, context);
+
+ return {
+ schema: resolved,
+ warnings: context.warnings,
+ };
+}
+
+/**
+ * Recursively resolve a schema node
+ */
+function resolveNode(node: unknown, context: ResolveContext): unknown {
+ // Handle non-objects
+ if (!isObject(node)) {
+ return node;
+ }
+
+ const obj = node as Record;
+
+ // Check if this is a $ref node
+ if (typeof obj['$ref'] === 'string') {
+ return resolveRef(obj['$ref'], obj, context);
+ }
+
+ // Recursively resolve all properties
+ const resolved: Record = {};
+
+ for (const [key, value] of Object.entries(obj)) {
+ const previousPath = context.currentPath;
+ context.currentPath = `${context.currentPath}/${encodeJsonPointerSegment(key)}`;
+
+ if (Array.isArray(value)) {
+ resolved[key] = value.map((item, index) => {
+ const itemPath = context.currentPath;
+ context.currentPath = `${itemPath}/${index}`;
+ const resolvedItem = resolveNode(item, context);
+ context.currentPath = itemPath;
+ return resolvedItem;
+ });
+ } else {
+ resolved[key] = resolveNode(value, context);
+ }
+
+ context.currentPath = previousPath;
+ }
+
+ return resolved;
+}
+
+/**
+ * Resolve a $ref pointer
+ */
+function resolveRef(
+ ref: string,
+ refNode: Record,
+ context: ResolveContext
+): unknown {
+ // Check for external references
+ if (isExternalRef(ref)) {
+ context.warnings.push(
+ `External reference not resolved: ${ref} at ${context.currentPath || '/'}`
+ );
+ // Return the $ref node as-is for external refs
+ return refNode;
+ }
+
+ // Check for circular reference
+ if (context.resolving.has(ref)) {
+ context.warnings.push(`Circular reference detected: ${ref} at ${context.currentPath || '/'}`);
+ // Return a placeholder to break the cycle
+ return {
+ $circularRef: ref,
+ $comment: 'Circular reference - see original location',
+ };
+ }
+
+ // Check cache
+ if (context.cache.has(ref)) {
+ return context.cache.get(ref);
+ }
+
+ // Mark as currently resolving
+ context.resolving.add(ref);
+
+ try {
+ // Resolve the reference
+ const target = resolvePointer(ref, context.root);
+
+ if (target === undefined) {
+ context.warnings.push(`Reference not found: ${ref} at ${context.currentPath || '/'}`);
+ // Return the $ref node as-is if target not found
+ return refNode;
+ }
+
+ // Recursively resolve the target (it may contain more $refs)
+ const resolved = resolveNode(target, context);
+
+ // Merge any sibling properties from the $ref node
+ // JSON Schema allows properties alongside $ref in draft 2019-09+
+ const siblings = extractSiblingProperties(refNode);
+ const merged = mergeSiblings(resolved, siblings);
+
+ // Cache the result
+ context.cache.set(ref, merged);
+
+ return merged;
+ } finally {
+ // Remove from resolving set
+ context.resolving.delete(ref);
+ }
+}
+
+/**
+ * Check if a reference is external (http://, https://, file://)
+ */
+function isExternalRef(ref: string): boolean {
+ return (
+ ref.startsWith('http://') ||
+ ref.startsWith('https://') ||
+ ref.startsWith('file://') ||
+ // Relative file references (not starting with #)
+ (!ref.startsWith('#') &&
+ (ref.endsWith('.json') || ref.endsWith('.yaml') || ref.endsWith('.yml')))
+ );
+}
+
+/**
+ * Resolve a JSON Pointer within a document
+ *
+ * Supports:
+ * - #/$defs/Name
+ * - #/definitions/Name
+ * - #/properties/field/items
+ *
+ * @param pointer - The JSON Pointer (e.g., '#/$defs/User')
+ * @param root - The root document
+ * @returns The resolved value or undefined if not found
+ */
+function resolvePointer(pointer: string, root: unknown): unknown {
+ // Handle empty or root pointer
+ if (pointer === '#' || pointer === '') {
+ return root;
+ }
+
+ // Remove the leading # if present
+ let path = pointer;
+ if (path.startsWith('#')) {
+ path = path.slice(1);
+ }
+
+ // Remove leading slash
+ if (path.startsWith('/')) {
+ path = path.slice(1);
+ }
+
+ // Handle empty path after normalization
+ if (!path) {
+ return root;
+ }
+
+ // Split into segments and navigate
+ const segments = path.split('/');
+ let current: unknown = root;
+
+ for (const segment of segments) {
+ if (!isObject(current) && !Array.isArray(current)) {
+ return undefined;
+ }
+
+ const decoded = decodeJsonPointerSegment(segment);
+
+ if (Array.isArray(current)) {
+ const index = parseInt(decoded, 10);
+ if (isNaN(index) || index < 0 || index >= current.length) {
+ return undefined;
+ }
+ current = current[index];
+ } else {
+ const obj = current as Record;
+ if (!(decoded in obj)) {
+ return undefined;
+ }
+ current = obj[decoded];
+ }
+ }
+
+ return current;
+}
+
+/**
+ * Decode a JSON Pointer segment (RFC 6901)
+ *
+ * ~0 -> ~
+ * ~1 -> /
+ */
+function decodeJsonPointerSegment(segment: string): string {
+ return segment.replace(/~1/g, '/').replace(/~0/g, '~');
+}
+
+/**
+ * Encode a JSON Pointer segment (RFC 6901)
+ *
+ * ~ -> ~0
+ * / -> ~1
+ */
+function encodeJsonPointerSegment(segment: string): string {
+ return segment.replace(/~/g, '~0').replace(/\//g, '~1');
+}
+
+/**
+ * Extract sibling properties from a $ref node
+ *
+ * In JSON Schema draft 2019-09+, properties alongside $ref are allowed
+ * and should be merged with the referenced schema.
+ */
+function extractSiblingProperties(refNode: Record): Record {
+ const siblings: Record = {};
+
+ for (const [key, value] of Object.entries(refNode)) {
+ if (key !== '$ref') {
+ siblings[key] = value;
+ }
+ }
+
+ return siblings;
+}
+
+/**
+ * Merge sibling properties with a resolved schema
+ */
+function mergeSiblings(resolved: unknown, siblings: Record): unknown {
+ // If no siblings, return as-is
+ if (Object.keys(siblings).length === 0) {
+ return resolved;
+ }
+
+ // If resolved is not an object, wrap in allOf
+ if (!isObject(resolved)) {
+ return {
+ allOf: [resolved, siblings],
+ };
+ }
+
+ // Merge properties, siblings override resolved
+ return {
+ ...(resolved as Record),
+ ...siblings,
+ };
+}
+
+/**
+ * Type guard for objects
+ */
+function isObject(value: unknown): value is Record {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
+/**
+ * Check if a schema contains any unresolved $refs
+ *
+ * @param schema - The schema to check
+ * @returns True if the schema contains $ref pointers
+ */
+export function hasUnresolvedRefs(schema: unknown): boolean {
+ if (!isObject(schema)) {
+ return false;
+ }
+
+ const obj = schema as Record;
+
+ // Check if this node is a $ref
+ if (typeof obj['$ref'] === 'string' && !obj['$circularRef']) {
+ return true;
+ }
+
+ // Check children
+ for (const value of Object.values(obj)) {
+ if (Array.isArray(value)) {
+ for (const item of value) {
+ if (hasUnresolvedRefs(item)) {
+ return true;
+ }
+ }
+ } else if (hasUnresolvedRefs(value)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Extract all $ref pointers from a schema
+ *
+ * @param schema - The schema to analyze
+ * @returns Array of { pointer, path } objects
+ */
+export function extractRefs(schema: unknown): Array<{ pointer: string; path: string }> {
+ const refs: Array<{ pointer: string; path: string }> = [];
+ collectRefs(schema, '', refs);
+ return refs;
+}
+
+/**
+ * Recursively collect $refs
+ */
+function collectRefs(
+ node: unknown,
+ path: string,
+ refs: Array<{ pointer: string; path: string }>
+): void {
+ if (!isObject(node)) {
+ return;
+ }
+
+ const obj = node as Record;
+
+ if (typeof obj['$ref'] === 'string') {
+ refs.push({ pointer: obj['$ref'], path: path || '/' });
+ }
+
+ for (const [key, value] of Object.entries(obj)) {
+ const childPath = `${path}/${encodeJsonPointerSegment(key)}`;
+
+ if (Array.isArray(value)) {
+ value.forEach((item, index) => {
+ collectRefs(item, `${childPath}/${index}`, refs);
+ });
+ } else {
+ collectRefs(value, childPath, refs);
+ }
+ }
+}
+
+/**
+ * Validate that all internal references in a schema are resolvable
+ *
+ * @param schema - The schema to validate
+ * @returns Object with valid flag and any error messages
+ */
+export function validateRefs(schema: unknown): {
+ valid: boolean;
+ errors: string[];
+} {
+ const errors: string[] = [];
+ const refs = extractRefs(schema);
+
+ for (const { pointer, path } of refs) {
+ // Skip external refs for this validation
+ if (isExternalRef(pointer)) {
+ continue;
+ }
+
+ const resolved = resolvePointer(pointer, schema);
+ if (resolved === undefined) {
+ errors.push(`Invalid reference at ${path}: ${pointer} not found`);
+ }
+ }
+
+ return {
+ valid: errors.length === 0,
+ errors,
+ };
+}
diff --git a/packages/differs.core/src/types.ts b/packages/differs.core/src/types.ts
new file mode 100644
index 0000000..c907e57
--- /dev/null
+++ b/packages/differs.core/src/types.ts
@@ -0,0 +1,347 @@
+/**
+ * Core schema types and utilities for Contractual differs
+ */
+
+// Re-export governance types from @contractual/types
+export type {
+ ChangeType,
+ ChangeSeverity,
+ RawChange,
+ Change,
+ DiffResult,
+ DiffSummary,
+ SuggestedBump,
+} from '@contractual/types';
+
+export { CHANGE_TYPE_SEVERITY } from '@contractual/types';
+
+// ============================================================================
+// JSON Schema Types
+// ============================================================================
+
+/**
+ * JSON Schema type values
+ */
+export type JSONSchemaType =
+ | 'string'
+ | 'number'
+ | 'integer'
+ | 'boolean'
+ | 'object'
+ | 'array'
+ | 'null';
+
+/**
+ * Normalized type representation (always an array for comparison)
+ */
+export type NormalizedType = JSONSchemaType[];
+
+/**
+ * JSON Schema constraint keys that can be tightened or loosened
+ */
+export type ConstraintKey =
+ | 'minimum'
+ | 'maximum'
+ | 'exclusiveMinimum'
+ | 'exclusiveMaximum'
+ | 'minLength'
+ | 'maxLength'
+ | 'minItems'
+ | 'maxItems'
+ | 'minProperties'
+ | 'maxProperties'
+ | 'minContains'
+ | 'maxContains'
+ | 'pattern'
+ | 'multipleOf'
+ | 'uniqueItems';
+
+/**
+ * Constraint comparison direction
+ */
+export type ConstraintDirection = 'min' | 'max' | 'exact';
+
+/**
+ * Constraint metadata for determining tightened vs loosened
+ */
+export interface ConstraintMeta {
+ readonly key: ConstraintKey;
+ readonly direction: ConstraintDirection;
+}
+
+/**
+ * Map of constraint keys to their comparison direction
+ */
+export const CONSTRAINT_DIRECTION: Record = {
+ minimum: 'min',
+ maximum: 'max',
+ exclusiveMinimum: 'min',
+ exclusiveMaximum: 'max',
+ minLength: 'min',
+ maxLength: 'max',
+ minItems: 'min',
+ maxItems: 'max',
+ minProperties: 'min',
+ maxProperties: 'max',
+ minContains: 'min',
+ maxContains: 'max',
+ pattern: 'exact',
+ multipleOf: 'exact',
+ uniqueItems: 'exact',
+};
+
+/**
+ * All constraint keys for iteration
+ */
+export const CONSTRAINT_KEYS: ConstraintKey[] = [
+ 'minimum',
+ 'maximum',
+ 'exclusiveMinimum',
+ 'exclusiveMaximum',
+ 'minLength',
+ 'maxLength',
+ 'minItems',
+ 'maxItems',
+ 'minProperties',
+ 'maxProperties',
+ 'minContains',
+ 'maxContains',
+ 'pattern',
+ 'multipleOf',
+ 'uniqueItems',
+];
+
+/**
+ * Composition keywords in JSON Schema
+ */
+export type CompositionKeyword = 'anyOf' | 'oneOf' | 'allOf' | 'if' | 'then' | 'else' | 'not';
+
+/**
+ * All composition keywords for iteration
+ */
+export const COMPOSITION_KEYWORDS: CompositionKeyword[] = [
+ 'anyOf',
+ 'oneOf',
+ 'allOf',
+ 'if',
+ 'then',
+ 'else',
+ 'not',
+];
+
+/**
+ * Metadata keys that are compared (patch-level changes)
+ */
+export type MetadataKey = 'description' | 'title' | 'default' | 'examples';
+
+/**
+ * All metadata keys for iteration
+ */
+export const METADATA_KEYS: MetadataKey[] = ['description', 'title', 'default', 'examples'];
+
+/**
+ * Annotation keys (patch-level changes per Strands API)
+ */
+export type AnnotationKey = 'deprecated' | 'readOnly' | 'writeOnly';
+
+/**
+ * All annotation keys for iteration
+ */
+export const ANNOTATION_KEYS: AnnotationKey[] = ['deprecated', 'readOnly', 'writeOnly'];
+
+/**
+ * Content keywords (patch-level changes per Strands API)
+ */
+export type ContentKey = 'contentEncoding' | 'contentMediaType' | 'contentSchema';
+
+/**
+ * All content keys for iteration
+ */
+export const CONTENT_KEYS: ContentKey[] = ['contentEncoding', 'contentMediaType', 'contentSchema'];
+
+/**
+ * Resolved JSON Schema object (refs already resolved)
+ */
+export interface ResolvedSchema {
+ // Schema identification
+ $schema?: string;
+ $id?: string;
+ $ref?: string;
+ $defs?: Record;
+
+ // Type
+ type?: JSONSchemaType | JSONSchemaType[];
+
+ // Metadata
+ title?: string;
+ description?: string;
+ default?: unknown;
+ examples?: unknown[];
+
+ // Annotations (Draft 2019-09+)
+ deprecated?: boolean;
+ readOnly?: boolean;
+ writeOnly?: boolean;
+
+ // Enum
+ enum?: unknown[];
+ const?: unknown;
+
+ // Format
+ format?: string;
+
+ // Numeric constraints
+ minimum?: number;
+ maximum?: number;
+ exclusiveMinimum?: number;
+ exclusiveMaximum?: number;
+ multipleOf?: number;
+
+ // String constraints
+ minLength?: number;
+ maxLength?: number;
+ pattern?: string;
+
+ // Content keywords (Draft 7+)
+ contentEncoding?: string;
+ contentMediaType?: string;
+ contentSchema?: ResolvedSchema;
+
+ // Object keywords
+ properties?: Record;
+ required?: string[];
+ additionalProperties?: boolean | ResolvedSchema;
+ minProperties?: number;
+ maxProperties?: number;
+ propertyNames?: ResolvedSchema;
+ patternProperties?: Record;
+ dependentRequired?: Record;
+ dependentSchemas?: Record;
+ unevaluatedProperties?: boolean | ResolvedSchema;
+
+ // Array keywords
+ items?: ResolvedSchema | ResolvedSchema[];
+ prefixItems?: ResolvedSchema[];
+ minItems?: number;
+ maxItems?: number;
+ uniqueItems?: boolean;
+ contains?: ResolvedSchema;
+ minContains?: number;
+ maxContains?: number;
+ unevaluatedItems?: boolean | ResolvedSchema;
+
+ // Composition
+ anyOf?: ResolvedSchema[];
+ oneOf?: ResolvedSchema[];
+ allOf?: ResolvedSchema[];
+ if?: ResolvedSchema;
+ then?: ResolvedSchema;
+ else?: ResolvedSchema;
+ not?: ResolvedSchema;
+
+ // Allow additional properties for extensibility
+ [key: string]: unknown;
+}
+
+/**
+ * Walker context for tracking traversal state
+ */
+export interface WalkerContext {
+ /** Current JSON Pointer path */
+ readonly path: string;
+ /** Depth of recursion (for cycle detection) */
+ readonly depth: number;
+ /** Maximum allowed depth */
+ readonly maxDepth: number;
+}
+
+/**
+ * Default maximum recursion depth
+ */
+export const DEFAULT_MAX_DEPTH = 100;
+
+/**
+ * Type guard to check if value is a schema object
+ */
+export function isSchemaObject(value: unknown): value is ResolvedSchema {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
+/**
+ * Type guard to check if value is an array of schemas
+ */
+export function isSchemaArray(value: unknown): value is ResolvedSchema[] {
+ return Array.isArray(value) && value.every(isSchemaObject);
+}
+
+/**
+ * Normalize type to array for consistent comparison
+ */
+export function normalizeType(type: JSONSchemaType | JSONSchemaType[] | undefined): NormalizedType {
+ if (type === undefined) {
+ return [];
+ }
+ if (Array.isArray(type)) {
+ return [...type].sort();
+ }
+ return [type];
+}
+
+/**
+ * Check if two arrays have the same elements (order-independent)
+ */
+export function arraysEqual(a: T[], b: T[]): boolean {
+ if (a.length !== b.length) return false;
+ const sortedA = [...a].sort();
+ const sortedB = [...b].sort();
+ return sortedA.every((val, idx) => val === sortedB[idx]);
+}
+
+/**
+ * Deep equality check for JSON values
+ */
+export function deepEqual(a: unknown, b: unknown): boolean {
+ if (a === b) {
+ return true;
+ }
+
+ if (typeof a !== typeof b) {
+ return false;
+ }
+
+ if (a === null || b === null) return a === b;
+
+ if (Array.isArray(a) && Array.isArray(b)) {
+ if (a.length !== b.length) return false;
+ return a.every((val, idx) => deepEqual(val, b[idx]));
+ }
+
+ if (typeof a === 'object' && typeof b === 'object') {
+ const aObj = a as Record;
+ const bObj = b as Record;
+ const aKeys = Object.keys(aObj);
+ const bKeys = Object.keys(bObj);
+ if (aKeys.length !== bKeys.length) return false;
+ return aKeys.every((key) => deepEqual(aObj[key], bObj[key]));
+ }
+
+ return false;
+}
+
+/**
+ * Escape JSON Pointer segment according to RFC 6901
+ */
+export function escapeJsonPointer(segment: string): string {
+ return segment.replace(/~/g, '~0').replace(/\//g, '~1');
+}
+
+/**
+ * Join path segments into a JSON Pointer
+ */
+export function joinPath(basePath: string, ...segments: string[]): string {
+ const escaped = segments.map(escapeJsonPointer);
+ if (basePath === '') {
+ return escaped.length > 0 ? '/' + escaped.join('/') : '';
+ }
+ return basePath + '/' + escaped.join('/');
+}
diff --git a/packages/differs.core/src/walker.ts b/packages/differs.core/src/walker.ts
new file mode 100644
index 0000000..e1d47db
--- /dev/null
+++ b/packages/differs.core/src/walker.ts
@@ -0,0 +1,1578 @@
+/**
+ * JSON Schema structural walker
+ *
+ * Recursively walks two resolved JSON Schemas side-by-side (DFS)
+ * and emits RawChange for every structural difference.
+ */
+
+import type { ChangeType, RawChange, CONTENT_KEYS } from './types.js';
+import {
+ ANNOTATION_KEYS,
+ arraysEqual,
+ CONSTRAINT_DIRECTION,
+ CONSTRAINT_KEYS,
+ type ConstraintKey,
+ deepEqual,
+ DEFAULT_MAX_DEPTH,
+ isSchemaObject,
+ joinPath,
+ METADATA_KEYS,
+ type NormalizedType,
+ normalizeType,
+ type ResolvedSchema,
+} from './types.js';
+
+/**
+ * Walk two resolved JSON Schemas and emit changes
+ *
+ * @param oldSchema - The original schema (resolved, no $refs)
+ * @param newSchema - The new schema (resolved, no $refs)
+ * @param basePath - JSON Pointer base path (default: '')
+ * @returns Array of raw changes detected
+ */
+export function walk(oldSchema: unknown, newSchema: unknown, basePath: string = ''): RawChange[] {
+ return walkInternal(oldSchema, newSchema, basePath, 0);
+}
+
+/**
+ * Internal walk function with depth tracking
+ */
+function walkInternal(
+ oldSchema: unknown,
+ newSchema: unknown,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Prevent infinite recursion
+ if (depth > DEFAULT_MAX_DEPTH) {
+ return changes;
+ }
+
+ // Handle null/undefined schemas
+ if (oldSchema === undefined && newSchema === undefined) {
+ return changes;
+ }
+
+ // Normalize to objects for comparison
+ const oldObj = isSchemaObject(oldSchema) ? oldSchema : null;
+ const newObj = isSchemaObject(newSchema) ? newSchema : null;
+
+ // Schema added or removed entirely
+ if (oldObj === null && newObj !== null) {
+ changes.push({
+ path,
+ type: 'property-added',
+ oldValue: undefined,
+ newValue: newSchema,
+ });
+ return changes;
+ }
+
+ if (oldObj !== null && newObj === null) {
+ changes.push({
+ path,
+ type: 'property-removed',
+ oldValue: oldSchema,
+ newValue: undefined,
+ });
+ return changes;
+ }
+
+ // Both are non-object (boolean schemas in JSON Schema draft-06+)
+ if (oldObj === null && newObj === null) {
+ if (oldSchema !== newSchema) {
+ changes.push({
+ path,
+ type: 'unknown-change',
+ oldValue: oldSchema,
+ newValue: newSchema,
+ });
+ }
+ return changes;
+ }
+
+ // Both are schema objects - compare all aspects
+ const old = oldObj as ResolvedSchema;
+ const newS = newObj as ResolvedSchema;
+
+ // 1. Metadata changes (title, description, default, examples)
+ changes.push(...compareMetadata(old, newS, path));
+
+ // 2. Annotation changes (deprecated, readOnly, writeOnly)
+ changes.push(...compareAnnotations(old, newS, path));
+
+ // 3. Content keyword changes (contentEncoding, contentMediaType, contentSchema)
+ changes.push(...compareContentKeywords(old, newS, path, depth));
+
+ // 4. Type changes
+ changes.push(...compareType(old, newS, path));
+
+ // 5. Enum changes
+ changes.push(...compareEnum(old, newS, path));
+
+ // 6. Format changes
+ changes.push(...compareFormat(old, newS, path));
+
+ // 7. Constraint changes
+ changes.push(...compareConstraints(old, newS, path));
+
+ // 8. Properties changes (recurse)
+ changes.push(...compareProperties(old, newS, path, depth));
+
+ // 9. Required changes
+ changes.push(...compareRequired(old, newS, path));
+
+ // 10. additionalProperties changes
+ changes.push(...compareAdditionalProperties(old, newS, path, depth));
+
+ // 11. propertyNames changes
+ changes.push(...comparePropertyNames(old, newS, path, depth));
+
+ // 12. dependentRequired changes
+ changes.push(...compareDependentRequired(old, newS, path));
+
+ // 13. dependentSchemas changes
+ changes.push(...compareDependentSchemas(old, newS, path, depth));
+
+ // 14. unevaluatedProperties changes
+ changes.push(...compareUnevaluatedProperties(old, newS, path, depth));
+
+ // 15. Array items changes (recurse)
+ changes.push(...compareArrayItems(old, newS, path, depth));
+
+ // 16. unevaluatedItems changes
+ changes.push(...compareUnevaluatedItems(old, newS, path, depth));
+
+ // 17. minContains/maxContains changes
+ changes.push(...compareMinMaxContains(old, newS, path));
+
+ // 18. Composition changes (anyOf, oneOf, allOf, if/then/else, not)
+ changes.push(...compareComposition(old, newS, path, depth));
+
+ return changes;
+}
+
+/**
+ * Mapping of metadata keys to their change types
+ */
+const METADATA_CHANGE_TYPES: Readonly> = {
+ description: 'description-changed',
+ title: 'title-changed',
+ default: 'default-changed',
+ examples: 'examples-changed',
+} as const;
+
+/**
+ * Compare metadata fields (description, title, default, examples)
+ */
+function compareMetadata(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ for (const key of METADATA_KEYS) {
+ const oldValue = oldSchema[key];
+ const newValue = newSchema[key];
+
+ if (!deepEqual(oldValue, newValue)) {
+ changes.push({
+ path: joinPath(path, key),
+ type: METADATA_CHANGE_TYPES[key],
+ oldValue,
+ newValue,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Mapping of annotation keys to their change types
+ */
+const ANNOTATION_CHANGE_TYPES: Readonly> = {
+ deprecated: 'deprecated-changed',
+ readOnly: 'read-only-changed',
+ writeOnly: 'write-only-changed',
+} as const;
+
+/**
+ * Compare annotation fields (deprecated, readOnly, writeOnly)
+ * These are patch-level changes per Strands API
+ */
+function compareAnnotations(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ for (const key of ANNOTATION_KEYS) {
+ const oldValue = oldSchema[key];
+ const newValue = newSchema[key];
+
+ if (oldValue !== newValue) {
+ changes.push({
+ path: joinPath(path, key),
+ type: ANNOTATION_CHANGE_TYPES[key],
+ oldValue,
+ newValue,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Mapping of content keys to their change types
+ */
+const CONTENT_CHANGE_TYPES: Readonly> = {
+ contentEncoding: 'content-encoding-changed',
+ contentMediaType: 'content-media-type-changed',
+ contentSchema: 'content-schema-changed',
+} as const;
+
+/**
+ * Compare content keywords (contentEncoding, contentMediaType, contentSchema)
+ * These are patch-level changes per Strands API
+ */
+function compareContentKeywords(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Compare contentEncoding and contentMediaType (simple string values)
+ for (const key of ['contentEncoding', 'contentMediaType'] as const) {
+ const oldValue = oldSchema[key];
+ const newValue = newSchema[key];
+
+ if (oldValue !== newValue) {
+ changes.push({
+ path: joinPath(path, key),
+ type: CONTENT_CHANGE_TYPES[key],
+ oldValue,
+ newValue,
+ });
+ }
+ }
+
+ // Compare contentSchema (recurse into schema)
+ const oldContentSchema = oldSchema.contentSchema;
+ const newContentSchema = newSchema.contentSchema;
+
+ if (!deepEqual(oldContentSchema, newContentSchema)) {
+ if (isSchemaObject(oldContentSchema) && isSchemaObject(newContentSchema)) {
+ // Both are schemas - recurse but wrap all changes as content-schema-changed
+ const nestedChanges = walkInternal(
+ oldContentSchema,
+ newContentSchema,
+ joinPath(path, 'contentSchema'),
+ depth + 1
+ );
+ // If there are nested changes, report as content-schema-changed
+ if (nestedChanges.length > 0) {
+ changes.push({
+ path: joinPath(path, 'contentSchema'),
+ type: 'content-schema-changed',
+ oldValue: oldContentSchema,
+ newValue: newContentSchema,
+ });
+ }
+ } else {
+ // Schema added, removed, or type changed
+ changes.push({
+ path: joinPath(path, 'contentSchema'),
+ type: 'content-schema-changed',
+ oldValue: oldContentSchema,
+ newValue: newContentSchema,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare type field, detecting narrowed/widened/changed
+ */
+function compareType(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldType = normalizeType(oldSchema.type);
+ const newType = normalizeType(newSchema.type);
+
+ // No type defined in either
+ if (oldType.length === 0 && newType.length === 0) {
+ return changes;
+ }
+
+ // Types are identical
+ if (arraysEqual(oldType, newType)) {
+ return changes;
+ }
+
+ // Determine change type
+ const changeType = determineTypeChange(oldType, newType);
+
+ changes.push({
+ path: joinPath(path, 'type'),
+ type: changeType,
+ oldValue: oldSchema.type,
+ newValue: newSchema.type,
+ });
+
+ return changes;
+}
+
+/**
+ * Determine if type change is narrowed, widened, or changed
+ */
+function determineTypeChange(oldType: NormalizedType, newType: NormalizedType): ChangeType {
+ // Type added where none existed
+ if (oldType.length === 0 && newType.length > 0) {
+ return 'type-narrowed'; // Adding type constraint narrows
+ }
+
+ // Type removed where one existed
+ if (oldType.length > 0 && newType.length === 0) {
+ return 'type-widened'; // Removing type constraint widens
+ }
+
+ // Check if new is subset of old (narrowed)
+ const oldSet = new Set(oldType);
+ const newSet = new Set(newType);
+
+ const isSubset = newType.every((t) => oldSet.has(t));
+ const isSuperset = oldType.every((t) => newSet.has(t));
+
+ if (isSubset && !isSuperset) {
+ return 'type-narrowed'; // New allows fewer types
+ }
+
+ if (isSuperset && !isSubset) {
+ return 'type-widened'; // New allows more types
+ }
+
+ // Types changed incompatibly (neither subset nor superset)
+ return 'type-changed';
+}
+
+/**
+ * Compare enum values
+ */
+function compareEnum(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldEnum = oldSchema.enum;
+ const newEnum = newSchema.enum;
+
+ // Enum added
+ if (oldEnum === undefined && newEnum !== undefined) {
+ changes.push({
+ path: joinPath(path, 'enum'),
+ type: 'enum-added',
+ oldValue: undefined,
+ newValue: newEnum,
+ });
+ return changes;
+ }
+
+ // Enum removed
+ if (oldEnum !== undefined && newEnum === undefined) {
+ changes.push({
+ path: joinPath(path, 'enum'),
+ type: 'enum-removed',
+ oldValue: oldEnum,
+ newValue: undefined,
+ });
+ return changes;
+ }
+
+ // Both have enums - compare values
+ if (oldEnum !== undefined && newEnum !== undefined) {
+ // Find removed values
+ for (const oldValue of oldEnum) {
+ const exists = newEnum.some((v) => deepEqual(v, oldValue));
+ if (!exists) {
+ changes.push({
+ path: joinPath(path, 'enum'),
+ type: 'enum-value-removed',
+ oldValue,
+ newValue: undefined,
+ });
+ }
+ }
+
+ // Find added values
+ for (const newValue of newEnum) {
+ const exists = oldEnum.some((v) => deepEqual(v, newValue));
+ if (!exists) {
+ changes.push({
+ path: joinPath(path, 'enum'),
+ type: 'enum-value-added',
+ oldValue: undefined,
+ newValue,
+ });
+ }
+ }
+ }
+
+ // Also check const (single-value enum)
+ if (!deepEqual(oldSchema.const, newSchema.const)) {
+ if (oldSchema.const === undefined && newSchema.const !== undefined) {
+ changes.push({
+ path: joinPath(path, 'const'),
+ type: 'enum-added',
+ oldValue: undefined,
+ newValue: newSchema.const,
+ });
+ } else if (oldSchema.const !== undefined && newSchema.const === undefined) {
+ changes.push({
+ path: joinPath(path, 'const'),
+ type: 'enum-removed',
+ oldValue: oldSchema.const,
+ newValue: undefined,
+ });
+ } else {
+ changes.push({
+ path: joinPath(path, 'const'),
+ type: 'enum-value-removed',
+ oldValue: oldSchema.const,
+ newValue: newSchema.const,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare format field
+ */
+function compareFormat(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldFormat = oldSchema.format;
+ const newFormat = newSchema.format;
+
+ if (oldFormat === newFormat) {
+ return changes;
+ }
+
+ if (oldFormat === undefined && newFormat !== undefined) {
+ changes.push({
+ path: joinPath(path, 'format'),
+ type: 'format-added',
+ oldValue: undefined,
+ newValue: newFormat,
+ });
+ } else if (oldFormat !== undefined && newFormat === undefined) {
+ changes.push({
+ path: joinPath(path, 'format'),
+ type: 'format-removed',
+ oldValue: oldFormat,
+ newValue: undefined,
+ });
+ } else {
+ changes.push({
+ path: joinPath(path, 'format'),
+ type: 'format-changed',
+ oldValue: oldFormat,
+ newValue: newFormat,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Compare numeric and string constraints
+ */
+function compareConstraints(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ for (const key of CONSTRAINT_KEYS) {
+ const oldValue = oldSchema[key];
+ const newValue = newSchema[key];
+
+ if (deepEqual(oldValue, newValue)) {
+ continue;
+ }
+
+ const direction = CONSTRAINT_DIRECTION[key];
+ const changeType = determineConstraintChange(key, direction, oldValue, newValue);
+
+ changes.push({
+ path: joinPath(path, key),
+ type: changeType,
+ oldValue,
+ newValue,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Determine if constraint change is tightened or loosened
+ */
+function determineConstraintChange(
+ key: ConstraintKey,
+ direction: 'min' | 'max' | 'exact',
+ oldValue: unknown,
+ newValue: unknown
+): ChangeType {
+ // Handle special cases for minItems/maxItems
+ if (key === 'minItems') {
+ if (oldValue === undefined && typeof newValue === 'number') {
+ return 'min-items-increased';
+ }
+ if (typeof oldValue === 'number' && newValue === undefined) {
+ return 'constraint-loosened';
+ }
+ if (typeof oldValue === 'number' && typeof newValue === 'number') {
+ return newValue > oldValue ? 'min-items-increased' : 'constraint-loosened';
+ }
+ }
+
+ if (key === 'maxItems') {
+ if (oldValue === undefined && typeof newValue === 'number') {
+ return 'max-items-decreased';
+ }
+ if (typeof oldValue === 'number' && newValue === undefined) {
+ return 'constraint-loosened';
+ }
+ if (typeof oldValue === 'number' && typeof newValue === 'number') {
+ return newValue < oldValue ? 'max-items-decreased' : 'constraint-loosened';
+ }
+ }
+
+ // Pattern and multipleOf are exact - any change is significant
+ if (direction === 'exact') {
+ return 'constraint-tightened'; // Conservative: treat as tightening
+ }
+
+ // For min constraints: increasing tightens, decreasing loosens
+ if (direction === 'min') {
+ if (oldValue === undefined && newValue !== undefined) {
+ return 'constraint-tightened'; // Adding min constraint tightens
+ }
+ if (oldValue !== undefined && newValue === undefined) {
+ return 'constraint-loosened'; // Removing min constraint loosens
+ }
+ if (typeof oldValue === 'number' && typeof newValue === 'number') {
+ return newValue > oldValue ? 'constraint-tightened' : 'constraint-loosened';
+ }
+ }
+
+ // For max constraints: decreasing tightens, increasing loosens
+ if (direction === 'max') {
+ if (oldValue === undefined && newValue !== undefined) {
+ return 'constraint-tightened'; // Adding max constraint tightens
+ }
+ if (oldValue !== undefined && newValue === undefined) {
+ return 'constraint-loosened'; // Removing max constraint loosens
+ }
+ if (typeof oldValue === 'number' && typeof newValue === 'number') {
+ return newValue < oldValue ? 'constraint-tightened' : 'constraint-loosened';
+ }
+ }
+
+ // Handle uniqueItems specially
+ if (key === 'uniqueItems') {
+ if (newValue === true && oldValue !== true) {
+ return 'constraint-tightened';
+ }
+ if (newValue !== true && oldValue === true) {
+ return 'constraint-loosened';
+ }
+ }
+
+ return 'constraint-tightened'; // Conservative default
+}
+
+/**
+ * Compare object properties (recursive)
+ */
+function compareProperties(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldProps = oldSchema.properties ?? {};
+ const newProps = newSchema.properties ?? {};
+
+ const oldKeys = new Set(Object.keys(oldProps));
+ const newKeys = new Set(Object.keys(newProps));
+
+ // Find removed properties
+ for (const key of oldKeys) {
+ if (!newKeys.has(key)) {
+ changes.push({
+ path: joinPath(path, 'properties', key),
+ type: 'property-removed',
+ oldValue: oldProps[key],
+ newValue: undefined,
+ });
+ }
+ }
+
+ // Find added properties
+ for (const key of newKeys) {
+ if (!oldKeys.has(key)) {
+ changes.push({
+ path: joinPath(path, 'properties', key),
+ type: 'property-added',
+ oldValue: undefined,
+ newValue: newProps[key],
+ });
+ }
+ }
+
+ // Recurse into common properties
+ for (const key of oldKeys) {
+ if (newKeys.has(key)) {
+ const nestedChanges = walkInternal(
+ oldProps[key],
+ newProps[key],
+ joinPath(path, 'properties', key),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ // Also compare patternProperties if present
+ const oldPatternProps = oldSchema.patternProperties ?? {};
+ const newPatternProps = newSchema.patternProperties ?? {};
+ const oldPatternKeys = new Set(Object.keys(oldPatternProps));
+ const newPatternKeys = new Set(Object.keys(newPatternProps));
+
+ for (const pattern of oldPatternKeys) {
+ if (!newPatternKeys.has(pattern)) {
+ changes.push({
+ path: joinPath(path, 'patternProperties', pattern),
+ type: 'property-removed',
+ oldValue: oldPatternProps[pattern],
+ newValue: undefined,
+ });
+ }
+ }
+
+ for (const pattern of newPatternKeys) {
+ if (!oldPatternKeys.has(pattern)) {
+ changes.push({
+ path: joinPath(path, 'patternProperties', pattern),
+ type: 'property-added',
+ oldValue: undefined,
+ newValue: newPatternProps[pattern],
+ });
+ }
+ }
+
+ for (const pattern of oldPatternKeys) {
+ if (newPatternKeys.has(pattern)) {
+ const nestedChanges = walkInternal(
+ oldPatternProps[pattern],
+ newPatternProps[pattern],
+ joinPath(path, 'patternProperties', pattern),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare required array
+ */
+function compareRequired(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldRequired = new Set(oldSchema.required ?? []);
+ const newRequired = new Set(newSchema.required ?? []);
+
+ // Find removed required fields
+ for (const field of oldRequired) {
+ if (!newRequired.has(field)) {
+ changes.push({
+ path: joinPath(path, 'required'),
+ type: 'required-removed',
+ oldValue: field,
+ newValue: undefined,
+ });
+ }
+ }
+
+ // Find added required fields
+ for (const field of newRequired) {
+ if (!oldRequired.has(field)) {
+ changes.push({
+ path: joinPath(path, 'required'),
+ type: 'required-added',
+ oldValue: undefined,
+ newValue: field,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare additionalProperties
+ */
+function compareAdditionalProperties(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldAP = oldSchema.additionalProperties;
+ const newAP = newSchema.additionalProperties;
+
+ // No change
+ if (deepEqual(oldAP, newAP)) {
+ return changes;
+ }
+
+ // Normalize: undefined means allowed (true)
+ const oldAllows = oldAP !== false;
+ const newAllows = newAP !== false;
+
+ // Check for denied/allowed transitions
+ if (oldAllows && !newAllows) {
+ changes.push({
+ path: joinPath(path, 'additionalProperties'),
+ type: 'additional-properties-denied',
+ oldValue: oldAP,
+ newValue: newAP,
+ });
+ return changes;
+ }
+
+ if (!oldAllows && newAllows) {
+ changes.push({
+ path: joinPath(path, 'additionalProperties'),
+ type: 'additional-properties-allowed',
+ oldValue: oldAP,
+ newValue: newAP,
+ });
+ return changes;
+ }
+
+ // Both allow but with different schemas
+ if (isSchemaObject(oldAP) && isSchemaObject(newAP)) {
+ const nestedChanges = walkInternal(
+ oldAP,
+ newAP,
+ joinPath(path, 'additionalProperties'),
+ depth + 1
+ );
+ if (nestedChanges.length > 0) {
+ changes.push(...nestedChanges);
+ }
+ return changes;
+ }
+
+ // One is boolean, one is schema, or other differences
+ if (oldAP !== newAP) {
+ changes.push({
+ path: joinPath(path, 'additionalProperties'),
+ type: 'additional-properties-changed',
+ oldValue: oldAP,
+ newValue: newAP,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Compare propertyNames schema
+ */
+function comparePropertyNames(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldPN = oldSchema.propertyNames;
+ const newPN = newSchema.propertyNames;
+
+ if (deepEqual(oldPN, newPN)) {
+ return changes;
+ }
+
+ // Any change to propertyNames is complex and requires manual review
+ if (isSchemaObject(oldPN) && isSchemaObject(newPN)) {
+ // Could recurse, but propertyNames changes are fundamentally unknown
+ changes.push({
+ path: joinPath(path, 'propertyNames'),
+ type: 'property-names-changed',
+ oldValue: oldPN,
+ newValue: newPN,
+ });
+ } else if (oldPN !== undefined || newPN !== undefined) {
+ changes.push({
+ path: joinPath(path, 'propertyNames'),
+ type: 'property-names-changed',
+ oldValue: oldPN,
+ newValue: newPN,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Compare dependentRequired (Draft 2019-09+)
+ */
+function compareDependentRequired(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldDR = oldSchema.dependentRequired ?? {};
+ const newDR = newSchema.dependentRequired ?? {};
+
+ const oldKeys = new Set(Object.keys(oldDR));
+ const newKeys = new Set(Object.keys(newDR));
+
+ // Find removed dependencies (non-breaking)
+ for (const key of oldKeys) {
+ if (!newKeys.has(key)) {
+ changes.push({
+ path: joinPath(path, 'dependentRequired', key),
+ type: 'dependent-required-removed',
+ oldValue: oldDR[key],
+ newValue: undefined,
+ });
+ }
+ }
+
+ // Find added dependencies (breaking)
+ for (const key of newKeys) {
+ if (!oldKeys.has(key)) {
+ changes.push({
+ path: joinPath(path, 'dependentRequired', key),
+ type: 'dependent-required-added',
+ oldValue: undefined,
+ newValue: newDR[key],
+ });
+ }
+ }
+
+ // Compare modified dependencies
+ for (const key of oldKeys) {
+ if (newKeys.has(key)) {
+ const oldReqs = new Set(oldDR[key] ?? []);
+ const newReqs = new Set(newDR[key] ?? []);
+
+ // Find removed requirements (non-breaking)
+ for (const req of oldReqs) {
+ if (!newReqs.has(req)) {
+ changes.push({
+ path: joinPath(path, 'dependentRequired', key),
+ type: 'dependent-required-removed',
+ oldValue: req,
+ newValue: undefined,
+ });
+ }
+ }
+
+ // Find added requirements (breaking)
+ for (const req of newReqs) {
+ if (!oldReqs.has(req)) {
+ changes.push({
+ path: joinPath(path, 'dependentRequired', key),
+ type: 'dependent-required-added',
+ oldValue: undefined,
+ newValue: req,
+ });
+ }
+ }
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare dependentSchemas (Draft 2019-09+)
+ */
+function compareDependentSchemas(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldDS = oldSchema.dependentSchemas ?? {};
+ const newDS = newSchema.dependentSchemas ?? {};
+
+ const oldKeys = new Set(Object.keys(oldDS));
+ const newKeys = new Set(Object.keys(newDS));
+ const allKeys = new Set([...oldKeys, ...newKeys]);
+
+ for (const key of allKeys) {
+ const oldValue = oldDS[key];
+ const newValue = newDS[key];
+
+ if (!deepEqual(oldValue, newValue)) {
+ // dependentSchemas changes require manual review
+ changes.push({
+ path: joinPath(path, 'dependentSchemas', key),
+ type: 'dependent-schemas-changed',
+ oldValue,
+ newValue,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare unevaluatedProperties (Draft 2019-09+)
+ */
+function compareUnevaluatedProperties(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldUP = oldSchema.unevaluatedProperties;
+ const newUP = newSchema.unevaluatedProperties;
+
+ if (deepEqual(oldUP, newUP)) {
+ return changes;
+ }
+
+ // unevaluatedProperties changes require manual review
+ changes.push({
+ path: joinPath(path, 'unevaluatedProperties'),
+ type: 'unevaluated-properties-changed',
+ oldValue: oldUP,
+ newValue: newUP,
+ });
+
+ return changes;
+}
+
+/**
+ * Compare array items schema (recursive)
+ */
+function compareArrayItems(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldItems = oldSchema.items;
+ const newItems = newSchema.items;
+
+ // Compare single items schema
+ if (isSchemaObject(oldItems) && isSchemaObject(newItems)) {
+ const nestedChanges = walkInternal(oldItems, newItems, joinPath(path, 'items'), depth + 1);
+ changes.push(...nestedChanges);
+ } else if (oldItems !== undefined || newItems !== undefined) {
+ // Items added, removed, or changed type (array to object or vice versa)
+ if (!deepEqual(oldItems, newItems)) {
+ // Handle tuple items (array of schemas)
+ if (Array.isArray(oldItems) && Array.isArray(newItems)) {
+ const maxLen = Math.max(oldItems.length, newItems.length);
+ for (let i = 0; i < maxLen; i++) {
+ const nestedChanges = walkInternal(
+ oldItems[i],
+ newItems[i],
+ joinPath(path, 'items', String(i)),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ } else if (Array.isArray(oldItems) !== Array.isArray(newItems)) {
+ // Structural change between tuple and list validation
+ changes.push({
+ path: joinPath(path, 'items'),
+ type: 'items-changed',
+ oldValue: oldItems,
+ newValue: newItems,
+ });
+ } else if (oldItems === undefined || newItems === undefined) {
+ changes.push({
+ path: joinPath(path, 'items'),
+ type: 'items-changed',
+ oldValue: oldItems,
+ newValue: newItems,
+ });
+ }
+ }
+ }
+
+ // Compare prefixItems (JSON Schema draft 2020-12)
+ const oldPrefixItems = oldSchema.prefixItems;
+ const newPrefixItems = newSchema.prefixItems;
+
+ if (Array.isArray(oldPrefixItems) || Array.isArray(newPrefixItems)) {
+ const oldArr = oldPrefixItems ?? [];
+ const newArr = newPrefixItems ?? [];
+ const maxLen = Math.max(oldArr.length, newArr.length);
+
+ for (let i = 0; i < maxLen; i++) {
+ const nestedChanges = walkInternal(
+ oldArr[i],
+ newArr[i],
+ joinPath(path, 'prefixItems', String(i)),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ // Compare contains schema
+ if (oldSchema.contains !== undefined || newSchema.contains !== undefined) {
+ if (!deepEqual(oldSchema.contains, newSchema.contains)) {
+ if (isSchemaObject(oldSchema.contains) && isSchemaObject(newSchema.contains)) {
+ const nestedChanges = walkInternal(
+ oldSchema.contains,
+ newSchema.contains,
+ joinPath(path, 'contains'),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ } else {
+ changes.push({
+ path: joinPath(path, 'contains'),
+ type: 'items-changed',
+ oldValue: oldSchema.contains,
+ newValue: newSchema.contains,
+ });
+ }
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare unevaluatedItems (Draft 2020-12)
+ */
+function compareUnevaluatedItems(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldUI = oldSchema.unevaluatedItems;
+ const newUI = newSchema.unevaluatedItems;
+
+ if (deepEqual(oldUI, newUI)) {
+ return changes;
+ }
+
+ // unevaluatedItems changes require manual review
+ changes.push({
+ path: joinPath(path, 'unevaluatedItems'),
+ type: 'unevaluated-items-changed',
+ oldValue: oldUI,
+ newValue: newUI,
+ });
+
+ return changes;
+}
+
+/**
+ * Compare minContains and maxContains (Draft 2019-09+)
+ */
+function compareMinMaxContains(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Compare minContains
+ const oldMinContains = oldSchema.minContains;
+ const newMinContains = newSchema.minContains;
+
+ if (oldMinContains !== newMinContains) {
+ changes.push({
+ path: joinPath(path, 'minContains'),
+ type: 'min-contains-changed',
+ oldValue: oldMinContains,
+ newValue: newMinContains,
+ });
+ }
+
+ // Compare maxContains
+ const oldMaxContains = oldSchema.maxContains;
+ const newMaxContains = newSchema.maxContains;
+
+ if (oldMaxContains !== newMaxContains) {
+ changes.push({
+ path: joinPath(path, 'maxContains'),
+ type: 'max-contains-changed',
+ oldValue: oldMaxContains,
+ newValue: newMaxContains,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Compare composition keywords (anyOf, oneOf, allOf, if/then/else, not)
+ *
+ * Provides detailed analysis of composition changes with granular change types
+ * aligned with Strands API classification.
+ */
+function compareComposition(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Compare anyOf
+ changes.push(...compareAnyOf(oldSchema, newSchema, path, depth));
+
+ // Compare oneOf
+ changes.push(...compareOneOf(oldSchema, newSchema, path, depth));
+
+ // Compare allOf
+ changes.push(...compareAllOf(oldSchema, newSchema, path, depth));
+
+ // Compare not
+ changes.push(...compareNot(oldSchema, newSchema, path, depth));
+
+ // Compare if/then/else
+ changes.push(...compareIfThenElse(oldSchema, newSchema, path, depth));
+
+ return changes;
+}
+
+/**
+ * Compare anyOf composition (option additions are breaking, removals are non-breaking)
+ */
+function compareAnyOf(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldAnyOf = oldSchema.anyOf;
+ const newAnyOf = newSchema.anyOf;
+
+ // No anyOf in either
+ if (oldAnyOf === undefined && newAnyOf === undefined) {
+ return changes;
+ }
+
+ // anyOf added
+ if (oldAnyOf === undefined && newAnyOf !== undefined) {
+ for (let i = 0; i < newAnyOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'anyOf', String(i)),
+ type: 'anyof-option-added',
+ oldValue: undefined,
+ newValue: newAnyOf[i],
+ });
+ }
+ return changes;
+ }
+
+ // anyOf removed
+ if (oldAnyOf !== undefined && newAnyOf === undefined) {
+ for (let i = 0; i < oldAnyOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'anyOf', String(i)),
+ type: 'anyof-option-removed',
+ oldValue: oldAnyOf[i],
+ newValue: undefined,
+ });
+ }
+ return changes;
+ }
+
+ // Both have anyOf - compare options
+ if (oldAnyOf !== undefined && newAnyOf !== undefined) {
+ const matched = matchCompositionOptions(oldAnyOf, newAnyOf);
+
+ // Report removed options
+ for (const idx of matched.removed) {
+ changes.push({
+ path: joinPath(path, 'anyOf', String(idx)),
+ type: 'anyof-option-removed',
+ oldValue: oldAnyOf[idx],
+ newValue: undefined,
+ });
+ }
+
+ // Report added options
+ for (const idx of matched.added) {
+ changes.push({
+ path: joinPath(path, 'anyOf', String(idx)),
+ type: 'anyof-option-added',
+ oldValue: undefined,
+ newValue: newAnyOf[idx],
+ });
+ }
+
+ // Recurse into matched options for nested changes
+ for (const [oldIdx, newIdx] of matched.matched) {
+ const nestedChanges = walkInternal(
+ oldAnyOf[oldIdx],
+ newAnyOf[newIdx],
+ joinPath(path, 'anyOf', String(newIdx)),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare oneOf composition (option additions are breaking, removals are non-breaking)
+ */
+function compareOneOf(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldOneOf = oldSchema.oneOf;
+ const newOneOf = newSchema.oneOf;
+
+ // No oneOf in either
+ if (oldOneOf === undefined && newOneOf === undefined) {
+ return changes;
+ }
+
+ // oneOf added
+ if (oldOneOf === undefined && newOneOf !== undefined) {
+ for (let i = 0; i < newOneOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'oneOf', String(i)),
+ type: 'oneof-option-added',
+ oldValue: undefined,
+ newValue: newOneOf[i],
+ });
+ }
+ return changes;
+ }
+
+ // oneOf removed
+ if (oldOneOf !== undefined && newOneOf === undefined) {
+ for (let i = 0; i < oldOneOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'oneOf', String(i)),
+ type: 'oneof-option-removed',
+ oldValue: oldOneOf[i],
+ newValue: undefined,
+ });
+ }
+ return changes;
+ }
+
+ // Both have oneOf - compare options
+ if (oldOneOf !== undefined && newOneOf !== undefined) {
+ const matched = matchCompositionOptions(oldOneOf, newOneOf);
+
+ // Report removed options
+ for (const idx of matched.removed) {
+ changes.push({
+ path: joinPath(path, 'oneOf', String(idx)),
+ type: 'oneof-option-removed',
+ oldValue: oldOneOf[idx],
+ newValue: undefined,
+ });
+ }
+
+ // Report added options
+ for (const idx of matched.added) {
+ changes.push({
+ path: joinPath(path, 'oneOf', String(idx)),
+ type: 'oneof-option-added',
+ oldValue: undefined,
+ newValue: newOneOf[idx],
+ });
+ }
+
+ // Recurse into matched options for nested changes
+ for (const [oldIdx, newIdx] of matched.matched) {
+ const nestedChanges = walkInternal(
+ oldOneOf[oldIdx],
+ newOneOf[newIdx],
+ joinPath(path, 'oneOf', String(newIdx)),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare allOf composition (member additions are breaking, removals are non-breaking)
+ */
+function compareAllOf(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldAllOf = oldSchema.allOf;
+ const newAllOf = newSchema.allOf;
+
+ // No allOf in either
+ if (oldAllOf === undefined && newAllOf === undefined) {
+ return changes;
+ }
+
+ // allOf added
+ if (oldAllOf === undefined && newAllOf !== undefined) {
+ for (let i = 0; i < newAllOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'allOf', String(i)),
+ type: 'allof-member-added',
+ oldValue: undefined,
+ newValue: newAllOf[i],
+ });
+ }
+ return changes;
+ }
+
+ // allOf removed
+ if (oldAllOf !== undefined && newAllOf === undefined) {
+ for (let i = 0; i < oldAllOf.length; i++) {
+ changes.push({
+ path: joinPath(path, 'allOf', String(i)),
+ type: 'allof-member-removed',
+ oldValue: oldAllOf[i],
+ newValue: undefined,
+ });
+ }
+ return changes;
+ }
+
+ // Both have allOf - compare members
+ if (oldAllOf !== undefined && newAllOf !== undefined) {
+ const matched = matchCompositionOptions(oldAllOf, newAllOf);
+
+ // Report removed members
+ for (const idx of matched.removed) {
+ changes.push({
+ path: joinPath(path, 'allOf', String(idx)),
+ type: 'allof-member-removed',
+ oldValue: oldAllOf[idx],
+ newValue: undefined,
+ });
+ }
+
+ // Report added members
+ for (const idx of matched.added) {
+ changes.push({
+ path: joinPath(path, 'allOf', String(idx)),
+ type: 'allof-member-added',
+ oldValue: undefined,
+ newValue: newAllOf[idx],
+ });
+ }
+
+ // Recurse into matched members for nested changes
+ for (const [oldIdx, newIdx] of matched.matched) {
+ const nestedChanges = walkInternal(
+ oldAllOf[oldIdx],
+ newAllOf[newIdx],
+ joinPath(path, 'allOf', String(newIdx)),
+ depth + 1
+ );
+ changes.push(...nestedChanges);
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare not schema (any change is breaking)
+ */
+function compareNot(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldNot = oldSchema.not;
+ const newNot = newSchema.not;
+
+ if (deepEqual(oldNot, newNot)) {
+ return changes;
+ }
+
+ // Any change to not schema is breaking
+ changes.push({
+ path: joinPath(path, 'not'),
+ type: 'not-schema-changed',
+ oldValue: oldNot,
+ newValue: newNot,
+ });
+
+ return changes;
+}
+
+/**
+ * Compare if/then/else conditional schema (complex, requires manual review)
+ */
+function compareIfThenElse(
+ oldSchema: ResolvedSchema,
+ newSchema: ResolvedSchema,
+ path: string,
+ _depth: number
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ const oldIf = oldSchema.if;
+ const newIf = newSchema.if;
+ const oldThen = oldSchema.then;
+ const newThen = newSchema.then;
+ const oldElse = oldSchema.else;
+ const newElse = newSchema.else;
+
+ // Check if any of the if/then/else keywords changed
+ const ifChanged = !deepEqual(oldIf, newIf);
+ const thenChanged = !deepEqual(oldThen, newThen);
+ const elseChanged = !deepEqual(oldElse, newElse);
+
+ if (ifChanged || thenChanged || elseChanged) {
+ // Report as a single if-then-else-changed for simplicity
+ // These are complex and require manual review
+ changes.push({
+ path: joinPath(path, 'if'),
+ type: 'if-then-else-changed',
+ oldValue: { if: oldIf, then: oldThen, else: oldElse },
+ newValue: { if: newIf, then: newThen, else: newElse },
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Match composition options between old and new arrays
+ * Uses structural similarity to find corresponding options
+ */
+function matchCompositionOptions(
+ oldOptions: ResolvedSchema[],
+ newOptions: ResolvedSchema[]
+): {
+ matched: Array<[number, number]>;
+ removed: number[];
+ added: number[];
+} {
+ const matched: Array<[number, number]> = [];
+ const usedOld = new Set();
+ const usedNew = new Set();
+
+ // First pass: find exact matches
+ for (let i = 0; i < oldOptions.length; i++) {
+ for (let j = 0; j < newOptions.length; j++) {
+ if (usedNew.has(j)) continue;
+ if (deepEqual(oldOptions[i], newOptions[j])) {
+ matched.push([i, j]);
+ usedOld.add(i);
+ usedNew.add(j);
+ break;
+ }
+ }
+ }
+
+ // Second pass: match by position for remaining unmatched
+ // This handles cases where schemas are modified but at same position
+ for (let i = 0; i < oldOptions.length; i++) {
+ if (usedOld.has(i)) continue;
+ if (i < newOptions.length && !usedNew.has(i)) {
+ // Match by position as a heuristic
+ matched.push([i, i]);
+ usedOld.add(i);
+ usedNew.add(i);
+ }
+ }
+
+ // Collect removed (in old but not matched)
+ const removed: number[] = [];
+ for (let i = 0; i < oldOptions.length; i++) {
+ if (!usedOld.has(i)) {
+ removed.push(i);
+ }
+ }
+
+ // Collect added (in new but not matched)
+ const added: number[] = [];
+ for (let j = 0; j < newOptions.length; j++) {
+ if (!usedNew.has(j)) {
+ added.push(j);
+ }
+ }
+
+ return { matched, removed, added };
+}
diff --git a/packages/differs.core/tsconfig.build.json b/packages/differs.core/tsconfig.build.json
new file mode 100644
index 0000000..2333a75
--- /dev/null
+++ b/packages/differs.core/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true
+ },
+ "exclude": ["node_modules", "dist", "tests", "**/*.test.ts"]
+}
diff --git a/packages/differs.core/tsconfig.json b/packages/differs.core/tsconfig.json
new file mode 100644
index 0000000..e666b16
--- /dev/null
+++ b/packages/differs.core/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist", "tests"]
+}
diff --git a/packages/contract/.eslintrc b/packages/differs.json-schema/.eslintrc
similarity index 94%
rename from packages/contract/.eslintrc
rename to packages/differs.json-schema/.eslintrc
index f1ca71a..5e998f8 100644
--- a/packages/contract/.eslintrc
+++ b/packages/differs.json-schema/.eslintrc
@@ -1,3 +1,3 @@
{
"extends": "../../.eslintrc"
-}
\ No newline at end of file
+}
diff --git a/packages/differs.json-schema/.gitignore b/packages/differs.json-schema/.gitignore
new file mode 100644
index 0000000..83631f8
--- /dev/null
+++ b/packages/differs.json-schema/.gitignore
@@ -0,0 +1,3 @@
+dist/
+node_modules/
+*.tsbuildinfo
diff --git a/packages/differs.json-schema/README.md b/packages/differs.json-schema/README.md
new file mode 100644
index 0000000..98df287
--- /dev/null
+++ b/packages/differs.json-schema/README.md
@@ -0,0 +1,180 @@
+# @contractual/differs.json-schema
+
+Production-quality breaking change detection for JSON Schema.
+
+Detects and classifies structural changes between JSON Schema versions, recommending semantic version bumps (major/minor/patch).
+
+## Why?
+
+JSON Schema has 150M+ weekly npm downloads but **no production-quality breaking change detection tool**. This package fills that gap.
+
+## Installation
+
+```bash
+npm install @contractual/differs.json-schema
+```
+
+## Usage
+
+### Compare Schema Files
+
+```typescript
+import { diffJsonSchema } from '@contractual/differs.json-schema';
+
+const result = await diffJsonSchema('v1/user.schema.json', 'v2/user.schema.json');
+
+console.log(`Suggested bump: ${result.suggestedBump}`);
+console.log(`Breaking: ${result.summary.breaking}`);
+console.log(`Non-breaking: ${result.summary.nonBreaking}`);
+
+// List breaking changes
+for (const change of result.changes) {
+ if (change.severity === 'breaking') {
+ console.log(`β ${change.message}`);
+ }
+}
+```
+
+### Compare Schema Objects
+
+```typescript
+import { diffJsonSchemaObjects } from '@contractual/differs.json-schema';
+
+const oldSchema = { type: 'object', properties: { name: { type: 'string' } } };
+const newSchema = { type: 'object', properties: { name: { type: 'number' } } };
+
+const result = diffJsonSchemaObjects(oldSchema, newSchema);
+// result.suggestedBump === 'major'
+// result.changes[0].message === 'Type changed from "string" to "number"...'
+```
+
+### Quick Breaking Check
+
+```typescript
+import { hasBreakingChanges } from '@contractual/differs.json-schema';
+
+if (hasBreakingChanges(oldSchema, newSchema)) {
+ throw new Error('Breaking changes detected!');
+}
+```
+
+## Change Classifications
+
+### Breaking Changes (β major bump)
+
+| Category | Example |
+|----------|---------|
+| `property-removed` | Field deleted from schema |
+| `required-added` | Existing field became required |
+| `type-changed` | Type changed incompatibly |
+| `type-narrowed` | Union type reduced |
+| `enum-value-removed` | Enum option removed |
+| `constraint-tightened` | minLength/maxLength made stricter |
+| `additional-properties-denied` | Open schema closed |
+| `min-items-increased` | Array minimum increased |
+| `max-items-decreased` | Array maximum decreased |
+
+### Non-Breaking Changes (β minor bump)
+
+| Category | Example |
+|----------|---------|
+| `property-added` | New optional field |
+| `required-removed` | Field became optional |
+| `type-widened` | Type accepts more values |
+| `enum-value-added` | New enum option |
+| `constraint-loosened` | Constraints relaxed |
+| `additional-properties-allowed` | Closed schema opened |
+
+### Patch Changes (β patch bump)
+
+| Category | Example |
+|----------|---------|
+| `description-changed` | Documentation updated |
+| `title-changed` | Title updated |
+| `default-changed` | Default value updated |
+| `examples-changed` | Examples updated |
+
+## Advanced Usage
+
+### Resolve $refs
+
+```typescript
+import { resolveRefs } from '@contractual/differs.json-schema';
+
+const schema = {
+ type: 'object',
+ properties: {
+ user: { $ref: '#/$defs/User' }
+ },
+ $defs: {
+ User: { type: 'object', properties: { name: { type: 'string' } } }
+ }
+};
+
+const { schema: resolved, warnings } = resolveRefs(schema);
+// resolved.properties.user === { type: 'object', properties: { name: { type: 'string' } } }
+```
+
+### Custom Classification
+
+```typescript
+import { walk, classify, CLASSIFICATION_SETS } from '@contractual/differs.json-schema';
+
+// Get raw changes
+const rawChanges = walk(resolvedOld, resolvedNew, '');
+
+// Classify with custom rules
+for (const change of rawChanges) {
+ if (CLASSIFICATION_SETS.BREAKING.has(change.type)) {
+ console.log('Breaking:', change.path);
+ }
+}
+```
+
+## Supported JSON Schema Versions
+
+- Draft-07 (primary target)
+- Draft 2019-09
+- Draft 2020-12
+
+## API Reference
+
+### Main Functions
+
+- `diffJsonSchema(oldPath, newPath)` - Compare two schema files
+- `diffJsonSchemaObjects(oldSchema, newSchema)` - Compare two schema objects
+- `hasBreakingChanges(oldSchema, newSchema)` - Quick boolean check
+
+### Utilities
+
+- `resolveRefs(schema)` - Resolve all $ref pointers
+- `walk(oldSchema, newSchema, basePath)` - Low-level schema walker
+- `classify(change)` - Classify a raw change
+- `classifyPropertyAdded(change, newSchema)` - Context-aware property classification
+
+### Types
+
+```typescript
+interface DiffResult {
+ changes: Change[];
+ summary: DiffSummary;
+ suggestedBump: 'major' | 'minor' | 'patch' | 'none';
+}
+
+interface Change {
+ path: string;
+ severity: 'breaking' | 'non-breaking' | 'patch' | 'unknown';
+ category: string;
+ message: string;
+ oldValue?: unknown;
+ newValue?: unknown;
+}
+```
+
+## Part of Contractual
+
+This package is extracted from [Contractual](https://github.com/contractual-dev/contractual), the schema contract lifecycle orchestrator.
+
+## License
+
+MIT
diff --git a/packages/differs.json-schema/package.json b/packages/differs.json-schema/package.json
new file mode 100644
index 0000000..ff0cb02
--- /dev/null
+++ b/packages/differs.json-schema/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "@contractual/differs.json-schema",
+ "version": "0.1.0-dev.5",
+ "description": "Detect breaking changes between JSON Schema versions with semantic classification",
+ "license": "MIT",
+ "type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/differs.json-schema"
+ },
+ "homepage": "https://github.com/contractual-dev/contractual/tree/main/packages/differs.json-schema",
+ "bugs": {
+ "url": "https://github.com/contractual-dev/contractual/issues"
+ },
+ "keywords": [
+ "json-schema",
+ "diff",
+ "breaking-changes",
+ "semver",
+ "schema",
+ "api",
+ "compatibility",
+ "migration",
+ "validation"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "rimraf dist",
+ "build": "tsc -p tsconfig.build.json",
+ "build:watch": "tsc -p tsconfig.build.json --watch",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "lint": "eslint \"src/**/*.ts\""
+ },
+ "files": [
+ "dist",
+ "README.md"
+ ],
+ "dependencies": {
+ "@contractual/differs.core": "workspace:*",
+ "@contractual/types": "workspace:*"
+ },
+ "devDependencies": {
+ "rimraf": "^5.0.5",
+ "vitest": "^3.0.3"
+ },
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/differs.json-schema/src/compare.ts b/packages/differs.json-schema/src/compare.ts
new file mode 100644
index 0000000..07f126b
--- /dev/null
+++ b/packages/differs.json-schema/src/compare.ts
@@ -0,0 +1,293 @@
+/**
+ * Strands-compatible JSON Schema comparison API
+ *
+ * Provides schema comparison with output format matching the Strands API
+ * (https://strands.octue.com/api/compare-schemas)
+ */
+
+import type { ChangeSeverity, RawChange } from '@contractual/types';
+import type {
+ CompareResult,
+ CompareOptions,
+ StrandsTrace,
+ StrandsCompatibility,
+ StrandsVersion,
+ SemanticVersion,
+} from './types.js';
+import { resolveRefs, walk, classify, classifyPropertyAdded } from '@contractual/differs.core';
+
+/**
+ * Compare two JSON Schema objects and return Strands-compatible result
+ *
+ * @param sourceSchema - The source (old/baseline) schema object
+ * @param targetSchema - The target (new/current) schema object
+ * @param options - Optional comparison options
+ * @returns CompareResult in Strands API format
+ *
+ * @example
+ * ```typescript
+ * const source = { type: 'object', properties: { name: { type: 'string' } } };
+ * const target = { type: 'object', properties: { name: { type: 'number' } } };
+ *
+ * const result = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ * console.log(result.version); // 'major'
+ * console.log(result.newVersion); // { major: 2, minor: 0, patch: 0, version: '2.0.0' }
+ * ```
+ */
+export function compareSchemas(
+ sourceSchema: unknown,
+ targetSchema: unknown,
+ options?: CompareOptions
+): CompareResult {
+ // Resolve $refs in both schemas
+ const resolvedSourceResult = resolveRefs(sourceSchema);
+ const resolvedTargetResult = resolveRefs(targetSchema);
+
+ const resolvedSource = resolvedSourceResult.schema;
+ const resolvedTarget = resolvedTargetResult.schema;
+
+ // Walk both schemas and detect raw changes
+ const rawChanges = walk(resolvedSource, resolvedTarget, '');
+
+ // Classify changes and generate traces
+ const traces: StrandsTrace[] = [];
+ let hasBreaking = false;
+ let hasNonBreaking = false;
+ let hasPatch = false;
+ let hasUnknown = false;
+
+ for (const raw of rawChanges) {
+ const severity = classifyChange(raw, resolvedTarget);
+
+ // Track highest severity
+ switch (severity) {
+ case 'breaking':
+ hasBreaking = true;
+ break;
+ case 'non-breaking':
+ hasNonBreaking = true;
+ break;
+ case 'patch':
+ hasPatch = true;
+ break;
+ case 'unknown':
+ hasUnknown = true;
+ break;
+ }
+
+ // Generate trace
+ const trace = rawChangeToTrace(raw, severity);
+ traces.push(trace);
+ }
+
+ // Determine version bump
+ const version = determineVersion(hasBreaking, hasNonBreaking, hasPatch, hasUnknown, traces);
+
+ // Compute new version if current version provided
+ const newVersion = options?.currentVersion
+ ? computeNewVersion(options.currentVersion, version)
+ : null;
+
+ return {
+ version,
+ traces,
+ newVersion,
+ };
+}
+
+/**
+ * Classify a change, with context-aware classification for property-added
+ */
+function classifyChange(change: RawChange, newSchema: unknown): ChangeSeverity {
+ if (change.type === 'property-added') {
+ return classifyPropertyAdded(change, newSchema);
+ }
+ return classify(change);
+}
+
+/**
+ * Convert a RawChange to a Strands trace
+ */
+function rawChangeToTrace(change: RawChange, severity: ChangeSeverity): StrandsTrace {
+ const compatibility = severityToCompatibility(severity);
+
+ // Determine left/right paths based on change type
+ const isAddition =
+ change.type.includes('added') ||
+ change.type === 'type-widened' ||
+ change.type === 'constraint-loosened';
+ const isRemoval =
+ change.type.includes('removed') ||
+ change.type === 'type-narrowed' ||
+ change.type === 'constraint-tightened';
+
+ let left: string | null = change.path;
+ let right: string | null = change.path;
+
+ // For additions, left is null (didn't exist in source)
+ if (isAddition && change.oldValue === undefined) {
+ left = null;
+ }
+
+ // For removals, right is null (doesn't exist in target)
+ if (isRemoval && change.newValue === undefined) {
+ right = null;
+ }
+
+ return {
+ compatibility,
+ left,
+ right,
+ };
+}
+
+/**
+ * Map ChangeSeverity to Strands compatibility
+ */
+function severityToCompatibility(severity: ChangeSeverity): StrandsCompatibility {
+ switch (severity) {
+ case 'breaking':
+ return 'incompatible';
+ case 'non-breaking':
+ case 'patch':
+ return 'compatible';
+ case 'unknown':
+ default:
+ return 'unknown';
+ }
+}
+
+/**
+ * Determine the version bump level based on detected changes
+ */
+function determineVersion(
+ hasBreaking: boolean,
+ hasNonBreaking: boolean,
+ hasPatch: boolean,
+ hasUnknown: boolean,
+ traces: StrandsTrace[]
+): StrandsVersion {
+ // No changes = equal
+ if (traces.length === 0) {
+ return 'equal';
+ }
+
+ // If there are unknown changes, we can't determine version
+ if (hasUnknown && !hasBreaking && !hasNonBreaking) {
+ return null;
+ }
+
+ // Priority: breaking > non-breaking > patch
+ if (hasBreaking) {
+ return 'major';
+ }
+
+ if (hasNonBreaking) {
+ return 'minor';
+ }
+
+ if (hasPatch) {
+ return 'patch';
+ }
+
+ // Only unknown changes
+ return null;
+}
+
+/**
+ * Compute the new semantic version based on current version and bump level
+ */
+function computeNewVersion(
+ currentVersion: string,
+ bumpLevel: StrandsVersion
+): SemanticVersion | null {
+ if (bumpLevel === null || bumpLevel === 'equal') {
+ // Parse current version and return as-is for equal
+ const parsed = parseVersion(currentVersion);
+ if (!parsed) return null;
+ return bumpLevel === 'equal' ? parsed : null;
+ }
+
+ const parsed = parseVersion(currentVersion);
+ if (!parsed) {
+ return null;
+ }
+
+ let { major, minor, patch } = parsed;
+
+ switch (bumpLevel) {
+ case 'major':
+ major += 1;
+ minor = 0;
+ patch = 0;
+ break;
+ case 'minor':
+ minor += 1;
+ patch = 0;
+ break;
+ case 'patch':
+ patch += 1;
+ break;
+ }
+
+ return {
+ major,
+ minor,
+ patch,
+ version: `${major}.${minor}.${patch}`,
+ };
+}
+
+/**
+ * Parse a semver string into components
+ */
+function parseVersion(version: string): SemanticVersion | null {
+ // Remove 'v' prefix if present
+ const cleaned = version.startsWith('v') ? version.slice(1) : version;
+
+ // Match semver pattern (with optional prerelease/build)
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)/);
+ if (!match) {
+ return null;
+ }
+
+ const major = parseInt(match[1]!, 10);
+ const minor = parseInt(match[2]!, 10);
+ const patch = parseInt(match[3]!, 10);
+
+ return {
+ major,
+ minor,
+ patch,
+ version: `${major}.${minor}.${patch}`,
+ };
+}
+
+/**
+ * Compare two JSON Schema objects and return a simple compatibility result
+ *
+ * Convenience function for quick compatibility checks.
+ *
+ * @param sourceSchema - The source (old/baseline) schema object
+ * @param targetSchema - The target (new/current) schema object
+ * @returns 'compatible' | 'incompatible' | 'unknown'
+ */
+export function checkCompatibility(
+ sourceSchema: unknown,
+ targetSchema: unknown
+): StrandsCompatibility {
+ const result = compareSchemas(sourceSchema, targetSchema);
+
+ // If any trace is incompatible, overall is incompatible
+ if (result.traces.some((t) => t.compatibility === 'incompatible')) {
+ return 'incompatible';
+ }
+
+ // If any trace is unknown, overall is unknown
+ if (result.traces.some((t) => t.compatibility === 'unknown')) {
+ return 'unknown';
+ }
+
+ // All compatible
+ return 'compatible';
+}
diff --git a/packages/differs.json-schema/src/differ.ts b/packages/differs.json-schema/src/differ.ts
new file mode 100644
index 0000000..c533b4a
--- /dev/null
+++ b/packages/differs.json-schema/src/differ.ts
@@ -0,0 +1,78 @@
+/**
+ * JSON Schema Structural Differ
+ *
+ * Compares two JSON Schema files and detects structural changes,
+ * classifying them by severity for semver bump decisions.
+ */
+
+import { readFile } from 'node:fs/promises';
+import type { DiffResult } from '@contractual/types';
+import { resolveRefs, walk, assembleResult, formatChangeMessage } from '@contractual/differs.core';
+
+// Re-export for backward compatibility
+export { formatChangeMessage };
+
+/**
+ * Diff two JSON Schema files and detect structural changes
+ *
+ * @param oldPath - Path to the old/base schema file
+ * @param newPath - Path to the new/changed schema file
+ * @returns DiffResult with classified changes and suggested bump
+ */
+export async function diffJsonSchema(oldPath: string, newPath: string): Promise {
+ let oldContent: string;
+ let newContent: string;
+
+ try {
+ oldContent = await readFile(oldPath, 'utf-8');
+ } catch (error) {
+ throw new Error(
+ `Failed to read old schema file "${oldPath}": ${error instanceof Error ? error.message : String(error)}`
+ );
+ }
+
+ try {
+ newContent = await readFile(newPath, 'utf-8');
+ } catch (error) {
+ throw new Error(
+ `Failed to read new schema file "${newPath}": ${error instanceof Error ? error.message : String(error)}`
+ );
+ }
+
+ let oldSchema: unknown;
+ let newSchema: unknown;
+
+ try {
+ oldSchema = JSON.parse(oldContent);
+ } catch (error) {
+ throw new Error(
+ `Failed to parse old schema as JSON "${oldPath}": ${error instanceof Error ? error.message : String(error)}`
+ );
+ }
+
+ try {
+ newSchema = JSON.parse(newContent);
+ } catch (error) {
+ throw new Error(
+ `Failed to parse new schema as JSON "${newPath}": ${error instanceof Error ? error.message : String(error)}`
+ );
+ }
+
+ return diffJsonSchemaObjects(oldSchema, newSchema);
+}
+
+/**
+ * Diff two JSON Schema objects and detect structural changes
+ *
+ * @param oldSchema - The old/base schema object
+ * @param newSchema - The new/changed schema object
+ * @returns DiffResult with classified changes and suggested bump
+ */
+export function diffJsonSchemaObjects(oldSchema: unknown, newSchema: unknown): DiffResult {
+ const resolvedOld = resolveRefs(oldSchema).schema;
+ const resolvedNew = resolveRefs(newSchema).schema;
+
+ const rawChanges = walk(resolvedOld, resolvedNew, '');
+
+ return assembleResult(rawChanges, resolvedNew);
+}
diff --git a/packages/differs.json-schema/src/index.ts b/packages/differs.json-schema/src/index.ts
new file mode 100644
index 0000000..a23c624
--- /dev/null
+++ b/packages/differs.json-schema/src/index.ts
@@ -0,0 +1,81 @@
+/**
+ * @contractual/differs.json-schema
+ *
+ * Detect and classify breaking changes between JSON Schema versions.
+ *
+ * @packageDocumentation
+ */
+
+// =============================================================================
+// Strands-compatible API (primary)
+// =============================================================================
+
+export { compareSchemas, checkCompatibility } from './compare.js';
+
+// =============================================================================
+// Legacy file-based API (backward compatible)
+// =============================================================================
+
+export { diffJsonSchema, diffJsonSchemaObjects, formatChangeMessage } from './differ.js';
+
+// =============================================================================
+// Re-exports from @contractual/differs.core (backward compatibility)
+// =============================================================================
+
+export {
+ // Classification
+ classify,
+ classifyPropertyAdded,
+ classifyAll,
+ CLASSIFICATION_SETS,
+ // Ref resolution
+ resolveRefs,
+ hasUnresolvedRefs,
+ extractRefs,
+ validateRefs,
+ type ResolveResult,
+ // Walker
+ walk,
+ // Result assembly
+ assembleResult,
+ type AssembleOptions,
+ // Schema types and utilities
+ type ResolvedSchema,
+ type JSONSchemaType,
+ type NormalizedType,
+ type ConstraintKey,
+ type ConstraintDirection,
+ type CompositionKeyword,
+ type MetadataKey,
+ type AnnotationKey,
+ type ContentKey,
+ type WalkerContext,
+ isSchemaObject,
+ isSchemaArray,
+ normalizeType,
+ arraysEqual,
+ deepEqual,
+ escapeJsonPointer,
+ joinPath,
+ CONSTRAINT_KEYS,
+ CONSTRAINT_DIRECTION,
+ COMPOSITION_KEYWORDS,
+ METADATA_KEYS,
+ ANNOTATION_KEYS,
+ CONTENT_KEYS,
+ DEFAULT_MAX_DEPTH,
+} from '@contractual/differs.core';
+
+// =============================================================================
+// Strands API Types
+// =============================================================================
+
+export type {
+ CompareResult,
+ CompareOptions,
+ StrandsTrace,
+ StrandsCompatibility,
+ StrandsVersion,
+ SemanticVersion,
+ JsonSchemaDraft,
+} from './types.js';
diff --git a/packages/differs.json-schema/src/types.ts b/packages/differs.json-schema/src/types.ts
new file mode 100644
index 0000000..4ca6e5a
--- /dev/null
+++ b/packages/differs.json-schema/src/types.ts
@@ -0,0 +1,67 @@
+/**
+ * Strands API types for JSON Schema comparison
+ *
+ * These types are specific to the Strands-compatible comparison API.
+ * Core schema diffing types are in @contractual/differs.core.
+ */
+
+/**
+ * Strands compatibility classification for a trace
+ */
+export type StrandsCompatibility = 'incompatible' | 'compatible' | 'unknown';
+
+/**
+ * Strands version bump level
+ */
+export type StrandsVersion = 'equal' | 'patch' | 'minor' | 'major' | null;
+
+/**
+ * A single trace showing where schemas differ (Strands format)
+ */
+export interface StrandsTrace {
+ /** Compatibility status of this change */
+ readonly compatibility: StrandsCompatibility;
+ /** JSON Pointer path in the source (left) schema, null if added */
+ readonly left: string | null;
+ /** JSON Pointer path in the target (right) schema, null if removed */
+ readonly right: string | null;
+}
+
+/**
+ * Semantic version object
+ */
+export interface SemanticVersion {
+ readonly major: number;
+ readonly minor: number;
+ readonly patch: number;
+ readonly version: string;
+}
+
+/**
+ * Strands API response format
+ */
+export interface CompareResult {
+ /** Version bump level, null if unknown/error */
+ readonly version: StrandsVersion;
+ /** List of traces showing where schemas differ */
+ readonly traces: StrandsTrace[];
+ /** Computed new version based on current version + bump */
+ readonly newVersion: SemanticVersion | null;
+ /** Error or warning message */
+ readonly message?: string;
+}
+
+/**
+ * Options for schema comparison
+ */
+export interface CompareOptions {
+ /** Current version to compute newVersion from (e.g., "1.0.0") */
+ readonly currentVersion?: string;
+ /** Draft version for validation rules */
+ readonly draft?: JsonSchemaDraft;
+}
+
+/**
+ * Supported JSON Schema drafts
+ */
+export type JsonSchemaDraft = 'draft-07' | 'draft-2019-09' | 'draft-2020-12';
diff --git a/packages/differs.json-schema/tsconfig.build.json b/packages/differs.json-schema/tsconfig.build.json
new file mode 100644
index 0000000..2333a75
--- /dev/null
+++ b/packages/differs.json-schema/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true
+ },
+ "exclude": ["node_modules", "dist", "tests", "**/*.test.ts"]
+}
diff --git a/packages/differs.json-schema/tsconfig.json b/packages/differs.json-schema/tsconfig.json
new file mode 100644
index 0000000..e666b16
--- /dev/null
+++ b/packages/differs.json-schema/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist", "tests"]
+}
diff --git a/packages/differs.openapi/package.json b/packages/differs.openapi/package.json
new file mode 100644
index 0000000..6f12ad4
--- /dev/null
+++ b/packages/differs.openapi/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@contractual/differs.openapi",
+ "private": false,
+ "version": "0.1.0-dev.5",
+ "description": "OpenAPI 3.0/3.1 breaking change detection for Contractual",
+ "license": "MIT",
+ "type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/differs.openapi"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "rimraf dist",
+ "build": "tsc -p tsconfig.build.json"
+ },
+ "files": [
+ "dist",
+ "README.md"
+ ],
+ "dependencies": {
+ "@contractual/differs.core": "workspace:*",
+ "@contractual/types": "workspace:*",
+ "@redocly/openapi-core": "^1.0.0"
+ },
+ "devDependencies": {
+ "rimraf": "^5.0.5"
+ },
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/differs.openapi/src/differ.ts b/packages/differs.openapi/src/differ.ts
new file mode 100644
index 0000000..2d0cc51
--- /dev/null
+++ b/packages/differs.openapi/src/differ.ts
@@ -0,0 +1,40 @@
+/**
+ * OpenAPI Differ
+ *
+ * Compares two OpenAPI specifications and detects breaking changes.
+ * Supports OpenAPI 3.0 and 3.1.
+ */
+
+import type { DiffResult } from '@contractual/types';
+import { assembleResult } from '@contractual/differs.core';
+import { resolveOpenApiSpec } from './resolver.js';
+import { diffStructural } from './structural.js';
+
+/**
+ * Diff two OpenAPI specification files
+ *
+ * @param oldSpecPath - Path to the old/base OpenAPI spec file
+ * @param newSpecPath - Path to the new/changed OpenAPI spec file
+ * @returns DiffResult with classified changes and suggested bump
+ */
+export async function diffOpenApi(oldSpecPath: string, newSpecPath: string): Promise {
+ const oldSpec = await resolveOpenApiSpec(oldSpecPath);
+ const newSpec = await resolveOpenApiSpec(newSpecPath);
+
+ return diffOpenApiObjects(oldSpec, newSpec);
+}
+
+/**
+ * Diff two resolved OpenAPI spec objects directly
+ *
+ * @param oldSpec - The old/base OpenAPI spec object (fully resolved)
+ * @param newSpec - The new/changed OpenAPI spec object (fully resolved)
+ * @returns DiffResult with classified changes and suggested bump
+ */
+export function diffOpenApiObjects(
+ oldSpec: Record,
+ newSpec: Record
+): DiffResult {
+ const rawChanges = diffStructural(oldSpec, newSpec);
+ return assembleResult(rawChanges, newSpec);
+}
diff --git a/packages/differs.openapi/src/index.ts b/packages/differs.openapi/src/index.ts
new file mode 100644
index 0000000..8ae0302
--- /dev/null
+++ b/packages/differs.openapi/src/index.ts
@@ -0,0 +1,3 @@
+export { diffOpenApi, diffOpenApiObjects } from './differ.js';
+export { resolveOpenApiSpec } from './resolver.js';
+export { diffStructural } from './structural.js';
diff --git a/packages/differs.openapi/src/resolver.ts b/packages/differs.openapi/src/resolver.ts
new file mode 100644
index 0000000..4978e7a
--- /dev/null
+++ b/packages/differs.openapi/src/resolver.ts
@@ -0,0 +1,42 @@
+/**
+ * OpenAPI spec resolver using @redocly/openapi-core
+ *
+ * Handles both OpenAPI 3.0 and 3.1 specifications.
+ * Uses Redocly to bundle external refs into a single document,
+ * then uses the core ref-resolver to dereference internal $refs
+ * (which handles circular references safely).
+ */
+
+import { resolveRefs } from '@contractual/differs.core';
+
+/**
+ * Resolve an OpenAPI spec file to a fully dereferenced object
+ *
+ * @param specPath - Absolute or relative path to the OpenAPI spec file
+ * @returns The fully resolved OpenAPI document as a plain object
+ */
+export async function resolveOpenApiSpec(specPath: string): Promise> {
+ let bundle: typeof import('@redocly/openapi-core').bundle;
+ let loadConfig: typeof import('@redocly/openapi-core').loadConfig;
+
+ try {
+ const redocly = await import('@redocly/openapi-core');
+ bundle = redocly.bundle;
+ loadConfig = redocly.loadConfig;
+ } catch {
+ throw new Error(
+ 'OpenAPI diffing requires @redocly/openapi-core. ' +
+ 'Install it with: npm install @redocly/openapi-core'
+ );
+ }
+
+ // Bundle only (no dereference) β resolves external refs into one document
+ // but keeps internal $refs intact to avoid circular object references
+ const config = await loadConfig();
+ const result = await bundle({ ref: specPath, config });
+ const bundled = result.bundle.parsed as Record;
+
+ // Use our own ref-resolver which handles circular refs safely
+ const resolved = resolveRefs(bundled);
+ return resolved.schema as Record;
+}
diff --git a/packages/differs.openapi/src/structural.ts b/packages/differs.openapi/src/structural.ts
new file mode 100644
index 0000000..49ce505
--- /dev/null
+++ b/packages/differs.openapi/src/structural.ts
@@ -0,0 +1,317 @@
+/**
+ * OpenAPI structural differ
+ *
+ * Compares the structural layer of two OpenAPI specs:
+ * paths, operations, parameters, request bodies, responses.
+ * Schema-level diffing is delegated to @contractual/differs.core walker.
+ */
+
+import type { RawChange, ChangeType } from '@contractual/types';
+import { walk, escapeJsonPointer } from '@contractual/differs.core';
+
+const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'patch', 'options', 'head', 'trace'] as const;
+
+type PathsMap = Record>;
+type OperationMap = Record;
+
+/**
+ * Diff the structural layer of two resolved OpenAPI specs
+ */
+export function diffStructural(
+ oldSpec: Record,
+ newSpec: Record
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Diff top-level info metadata
+ const oldInfo = (oldSpec.info ?? {}) as Record;
+ const newInfo = (newSpec.info ?? {}) as Record;
+
+ if (oldInfo.description !== newInfo.description) {
+ changes.push({
+ path: '/info/description',
+ type: 'description-changed' as ChangeType,
+ oldValue: oldInfo.description,
+ newValue: newInfo.description,
+ });
+ }
+
+ if (oldInfo.title !== newInfo.title) {
+ changes.push({
+ path: '/info/title',
+ type: 'title-changed' as ChangeType,
+ oldValue: oldInfo.title,
+ newValue: newInfo.title,
+ });
+ }
+
+ const oldPaths = (oldSpec.paths ?? {}) as PathsMap;
+ const newPaths = (newSpec.paths ?? {}) as PathsMap;
+
+ // Diff paths
+ for (const path of Object.keys(oldPaths)) {
+ const escapedPath = escapeJsonPointer(path);
+
+ if (!(path in newPaths)) {
+ changes.push({
+ path: `/paths/${escapedPath}`,
+ type: 'path-removed' as ChangeType,
+ oldValue: path,
+ });
+ continue;
+ }
+
+ // Diff operations within matching paths
+ changes.push(...diffOperations(oldPaths[path], newPaths[path], path));
+ }
+
+ for (const path of Object.keys(newPaths)) {
+ if (!(path in oldPaths)) {
+ const escapedPath = escapeJsonPointer(path);
+ changes.push({
+ path: `/paths/${escapedPath}`,
+ type: 'path-added' as ChangeType,
+ newValue: path,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Diff operations (HTTP methods) within a path
+ */
+function diffOperations(
+ oldPathItem: Record,
+ newPathItem: Record,
+ apiPath: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+ const escapedPath = escapeJsonPointer(apiPath);
+
+ for (const method of HTTP_METHODS) {
+ const oldOp = oldPathItem[method] as OperationMap | undefined;
+ const newOp = newPathItem[method] as OperationMap | undefined;
+
+ if (oldOp && !newOp) {
+ changes.push({
+ path: `/paths/${escapedPath}/${method}`,
+ type: 'operation-removed' as ChangeType,
+ oldValue: `${method.toUpperCase()} ${apiPath}`,
+ });
+ } else if (!oldOp && newOp) {
+ changes.push({
+ path: `/paths/${escapedPath}/${method}`,
+ type: 'operation-added' as ChangeType,
+ newValue: `${method.toUpperCase()} ${apiPath}`,
+ });
+ } else if (oldOp && newOp) {
+ // Both exist β diff metadata, parameters, request body, responses
+ const basePath = `/paths/${escapedPath}/${method}`;
+ changes.push(...diffOperationMetadata(oldOp, newOp, basePath));
+ changes.push(...diffParameters(oldOp, newOp, basePath));
+ changes.push(...diffRequestBody(oldOp, newOp, basePath));
+ changes.push(...diffResponses(oldOp, newOp, basePath));
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Diff operation-level metadata (description, summary, tags, deprecated)
+ */
+function diffOperationMetadata(
+ oldOp: OperationMap,
+ newOp: OperationMap,
+ basePath: string
+): RawChange[] {
+ const changes: RawChange[] = [];
+
+ // Description changed (patch)
+ if (oldOp.description !== newOp.description) {
+ changes.push({
+ path: `${basePath}/description`,
+ type: 'description-changed' as ChangeType,
+ oldValue: oldOp.description,
+ newValue: newOp.description,
+ });
+ }
+
+ // Summary changed (patch β treated as title)
+ if (oldOp.summary !== newOp.summary) {
+ changes.push({
+ path: `${basePath}/summary`,
+ type: 'title-changed' as ChangeType,
+ oldValue: oldOp.summary,
+ newValue: newOp.summary,
+ });
+ }
+
+ // Deprecated changed (patch)
+ if (oldOp.deprecated !== newOp.deprecated) {
+ changes.push({
+ path: `${basePath}/deprecated`,
+ type: 'deprecated-changed' as ChangeType,
+ oldValue: oldOp.deprecated,
+ newValue: newOp.deprecated,
+ });
+ }
+
+ return changes;
+}
+
+/**
+ * Diff parameters between two operations
+ */
+function diffParameters(oldOp: OperationMap, newOp: OperationMap, basePath: string): RawChange[] {
+ const changes: RawChange[] = [];
+ const oldParams = (oldOp.parameters ?? []) as Array>;
+ const newParams = (newOp.parameters ?? []) as Array>;
+
+ // Index by "in+name" for matching
+ const oldByKey = new Map(oldParams.map((p) => [`${p.in}:${p.name}`, p]));
+ const newByKey = new Map(newParams.map((p) => [`${p.in}:${p.name}`, p]));
+
+ for (const [key, oldParam] of oldByKey) {
+ if (!newByKey.has(key)) {
+ changes.push({
+ path: `${basePath}/parameters/${oldParam.name}`,
+ type: 'parameter-removed' as ChangeType,
+ oldValue: key,
+ });
+ } else {
+ const newParam = newByKey.get(key)!;
+
+ // Check required change
+ if (oldParam.required !== newParam.required) {
+ changes.push({
+ path: `${basePath}/parameters/${oldParam.name}/required`,
+ type: 'parameter-required-changed' as ChangeType,
+ oldValue: oldParam.required,
+ newValue: newParam.required,
+ });
+ }
+
+ // Diff parameter schemas using core walker
+ if (oldParam.schema && newParam.schema) {
+ const schemaChanges = walk(
+ oldParam.schema,
+ newParam.schema,
+ `${basePath}/parameters/${oldParam.name}/schema`
+ );
+ changes.push(...schemaChanges);
+ }
+ }
+ }
+
+ for (const [key, newParam] of newByKey) {
+ if (!oldByKey.has(key)) {
+ // Required parameter added = breaking, optional = non-breaking
+ // Store required flag in newValue so classifiers can check
+ changes.push({
+ path: `${basePath}/parameters/${newParam.name}`,
+ type: newParam.required
+ ? ('parameter-required-added' as ChangeType)
+ : ('parameter-added' as ChangeType),
+ newValue: key,
+ });
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Extract the primary schema from a content map (prefers application/json)
+ */
+function extractSchema(content: Record | undefined): unknown {
+ if (!content) return undefined;
+
+ // Prefer application/json, then first available
+ const jsonContent = content['application/json'] as Record | undefined;
+ if (jsonContent?.schema) return jsonContent.schema;
+
+ for (const mediaType of Object.values(content)) {
+ const mt = mediaType as Record;
+ if (mt?.schema) return mt.schema;
+ }
+
+ return undefined;
+}
+
+/**
+ * Diff request bodies between two operations
+ */
+function diffRequestBody(oldOp: OperationMap, newOp: OperationMap, basePath: string): RawChange[] {
+ const changes: RawChange[] = [];
+ const oldBody = oldOp.requestBody as Record | undefined;
+ const newBody = newOp.requestBody as Record | undefined;
+
+ if (oldBody && !newBody) {
+ changes.push({
+ path: `${basePath}/requestBody`,
+ type: 'request-body-removed' as ChangeType,
+ });
+ } else if (!oldBody && newBody) {
+ changes.push({
+ path: `${basePath}/requestBody`,
+ type: 'request-body-added' as ChangeType,
+ });
+ } else if (oldBody && newBody) {
+ const oldSchema = extractSchema(oldBody.content as Record);
+ const newSchema = extractSchema(newBody.content as Record);
+
+ if (oldSchema && newSchema) {
+ const schemaChanges = walk(oldSchema, newSchema, `${basePath}/requestBody/content/schema`);
+ changes.push(...schemaChanges);
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Diff responses between two operations
+ */
+function diffResponses(oldOp: OperationMap, newOp: OperationMap, basePath: string): RawChange[] {
+ const changes: RawChange[] = [];
+ const oldResponses = (oldOp.responses ?? {}) as Record>;
+ const newResponses = (newOp.responses ?? {}) as Record>;
+
+ for (const statusCode of Object.keys(oldResponses)) {
+ if (!(statusCode in newResponses)) {
+ changes.push({
+ path: `${basePath}/responses/${statusCode}`,
+ type: 'response-removed' as ChangeType,
+ oldValue: statusCode,
+ });
+ } else {
+ // Diff response schemas
+ const oldSchema = extractSchema(oldResponses[statusCode].content as Record);
+ const newSchema = extractSchema(newResponses[statusCode].content as Record);
+
+ if (oldSchema && newSchema) {
+ const schemaChanges = walk(
+ oldSchema,
+ newSchema,
+ `${basePath}/responses/${statusCode}/content/schema`
+ );
+ changes.push(...schemaChanges);
+ }
+ }
+ }
+
+ for (const statusCode of Object.keys(newResponses)) {
+ if (!(statusCode in oldResponses)) {
+ changes.push({
+ path: `${basePath}/responses/${statusCode}`,
+ type: 'response-added' as ChangeType,
+ newValue: statusCode,
+ });
+ }
+ }
+
+ return changes;
+}
diff --git a/packages/differs.openapi/tsconfig.build.json b/packages/differs.openapi/tsconfig.build.json
new file mode 100644
index 0000000..2333a75
--- /dev/null
+++ b/packages/differs.openapi/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true
+ },
+ "exclude": ["node_modules", "dist", "tests", "**/*.test.ts"]
+}
diff --git a/packages/differs.openapi/tsconfig.json b/packages/differs.openapi/tsconfig.json
new file mode 100644
index 0000000..e666b16
--- /dev/null
+++ b/packages/differs.openapi/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist", "tests"]
+}
diff --git a/packages/generators/contract/.eslintrc b/packages/generators/contract/.eslintrc
deleted file mode 100644
index 3280263..0000000
--- a/packages/generators/contract/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../.eslintrc"
-}
\ No newline at end of file
diff --git a/packages/generators/contract/contract.template.hbs b/packages/generators/contract/contract.template.hbs
deleted file mode 100644
index 4a96b12..0000000
--- a/packages/generators/contract/contract.template.hbs
+++ /dev/null
@@ -1,56 +0,0 @@
-import { z } from 'zod';
-import type { AppRouter } from '@ts-rest/core';
-import { initContract } from '@ts-rest/core';
-
-{{#if imports}}
- {{#each imports}}
- import { {{{@key}}} } from "./{{{this}}}"
- {{/each}}
-{{/if}}
-
-{{#if schemas}}
- {{#each schemas}}
- export const {{@key}} = {{{this}}};
-
- {{/each}}
-{{/if}}
-
-export const ApiContract = {
-{{#each endpoints}}
- {{alias}}: {
- method: '{{toUpperCase method}}' as const,
- path: "{{path}}",
- {{#if description}}
- description: `{{description}}`,
- {{/if}}
- {{#if parameters}}
- {{#includesType parameters "Path"}}
- pathParams: z.object({
- {{#each parameters}}{{#ifeq type "Path"}}'{{name}}': {{{schema}}},{{/ifeq}}{{/each}}
- }),
- {{/includesType}}
- {{#includesType parameters "Query"}}
- query: z.object({
- {{#each parameters}}{{#ifeq type "Query"}}'{{name}}': {{{schema}}},{{/ifeq}}{{/each}}
- }),
- {{/includesType}}
- {{#includesType parameters "Body"}}
- body: {{#each parameters}}{{#ifeq type "Body"}}{{{schema}}}{{/ifeq}}{{/each}},
- {{/includesType}}
- {{/if}}
- responses: {
- {{#each responses}}
- [{{statusCode}}]: {{{schema}}},
- {{/each}}
- },
- },
-{{/each}}
-} satisfies AppRouter;
-
-export const ApiOperations = {
-{{#each endpoints}}
- '{{toPlainWords alias}}': '{{alias}}',
-{{/each}}
-} satisfies Record;
-
-export const contract = initContract().router(ApiContract);
diff --git a/packages/generators/contract/index.ts b/packages/generators/contract/index.ts
deleted file mode 100644
index 8420b10..0000000
--- a/packages/generators/contract/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './src';
diff --git a/packages/generators/contract/package.json b/packages/generators/contract/package.json
deleted file mode 100644
index 8f12758..0000000
--- a/packages/generators/contract/package.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "name": "@contractual/generators.contract",
- "private": false,
- "version": "0.0.0",
- "license": "MIT",
- "type": "module",
- "module": "dist/index.js",
- "main": "dist/index.js",
- "repository": {
- "type": "git",
- "url": "https://github.com/contractual-dev/contractual.git",
- "directory": "packages/generators/client"
- },
- "exports": {
- ".": {
- "import": "./dist/index.js",
- "require": "./dist/index.js"
- }
- },
- "homepage": "https://contractual.dev",
- "bugs": {
- "url": "https://github.com/contractual-dev/contractual/issues"
- },
- "contributors": [
- {
- "name": "Omer Morad",
- "email": "omer.moradd@gmail.com"
- }
- ],
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/contractual-dev"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/contractual-dev"
- }
- ],
- "engines": {
- "node": ">=18.12.0"
- },
- "scripts": {
- "prebuild": "pnpm rimraf dist",
- "build": "tsc -p tsconfig.build.json",
- "build:watch": "tsc -p tsconfig.build.json --watch",
- "tester": "jest --coverage --verbose",
- "lint": "eslint '{src,test}/**/*.ts'"
- },
- "files": [
- "client.template.hbs",
- "dist",
- "README.md"
- ],
- "dependencies": {
- "@apidevtools/swagger-parser": "^10.1.1",
- "chalk": "^5.4.1",
- "handlebars": "^4.7.8",
- "openapi-types": "^12.1.3",
- "openapi-zod-client": "^1.18.2",
- "openapi3-ts": "^4.4.0"
- },
- "devDependencies": {
- "ora": "^8.1.1",
- "typescript": "~5.7.2"
- },
- "peerDependencies": {
- "typescript": ">=5.x"
- },
- "publishConfig": {
- "access": "public",
- "provenance": true
- }
-}
diff --git a/packages/generators/contract/src/command.ts b/packages/generators/contract/src/command.ts
deleted file mode 100644
index 05ac4aa..0000000
--- a/packages/generators/contract/src/command.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import type ora from 'ora';
-import { ContractCommandHandler, ContractFileGenerator, FileSystemHandler, SpinnerFactory } from './generator.js';
-import * as fs from 'node:fs';
-import SwaggerParser from '@apidevtools/swagger-parser';
-import { generateZodClientFromOpenAPI } from 'openapi-zod-client';
-import { createProgram } from 'typescript';
-import type chalk from 'chalk';
-
-export const createContractCommandHandler = (
- spinner: typeof ora,
- chalker: typeof chalk,
- logger: Console,
- apiSpecPath: string
-) => {
- const spinnerFactory = new SpinnerFactory(spinner);
-
- const fileGenerator = new ContractFileGenerator(
- spinnerFactory,
- generateZodClientFromOpenAPI,
- createProgram,
- new FileSystemHandler(fs)
- );
-
- return new ContractCommandHandler(
- spinnerFactory,
- new FileSystemHandler(fs),
- SwaggerParser,
- fileGenerator,
- logger,
- chalker,
- apiSpecPath
- );
-};
diff --git a/packages/generators/contract/src/generator.ts b/packages/generators/contract/src/generator.ts
deleted file mode 100644
index d98173c..0000000
--- a/packages/generators/contract/src/generator.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-import type SwaggerParser from '@apidevtools/swagger-parser';
-import * as path from 'node:path';
-import type { generateZodClientFromOpenAPI } from 'openapi-zod-client';
-import type { OpenAPIObject } from 'openapi3-ts/oas30';
-import * as process from 'node:process';
-import type { createProgram } from 'typescript';
-import { ModuleKind, ModuleResolutionKind, ScriptTarget } from 'typescript';
-import { createHandlebars } from './handlebars-helpers.js';
-import type ora from 'ora';
-import type * as fs from 'node:fs';
-import type chalk from 'chalk';
-
-export class SpinnerFactory {
- public constructor(private readonly spinner: typeof ora) {}
-
- public createSpinner(text: string) {
- return this.spinner(text);
- }
-}
-
-export class FileSystemHandler {
- public constructor(private readonly fileSystem: typeof fs) {}
-
- public exists(path: string): boolean {
- return this.fileSystem.existsSync(path);
- }
-
- public removeFile(path: string): void {
- this.fileSystem.rmSync(path);
- }
-}
-
-export class ContractFileGenerator {
- public constructor(
- private readonly spinnerFactory: SpinnerFactory,
- private readonly zodGenerator: typeof generateZodClientFromOpenAPI,
- private readonly programFactory: typeof createProgram,
- private readonly fileSystemHandler: FileSystemHandler
- ) {}
-
- public async generateFiles(openapiDocument: OpenAPIObject, destinationPath: string) {
- const spinner = this.spinnerFactory.createSpinner('Generating contract files..').start();
- const indexTsDestinationPath = path.resolve(destinationPath, 'index.ts');
-
- try {
- await this.zodGenerator({
- distPath: indexTsDestinationPath,
- openApiDoc: openapiDocument,
- templatePath: path.resolve(
- path.dirname(new URL(import.meta.url).pathname),
- '..',
- 'contract.template.hbs'
- ),
- prettierConfig: {
- tabWidth: 2,
- semi: true,
- singleQuote: true,
- trailingComma: 'all',
- bracketSpacing: true,
- arrowParens: 'always',
- },
- options: {
- additionalPropertiesDefaultValue: false,
- withAllResponses: true,
- withAlias: true,
- withDescription: false,
- withDefaultValues: false,
- },
- handlebars: createHandlebars(),
- });
-
- spinner.succeed('Generated Contractual contract');
- return indexTsDestinationPath;
- } catch (error) {
- spinner.fail('Failed to generate contract files.');
- throw error;
- }
- }
-
- public async compileFiles(destinationPath: string) {
- const spinner = this.spinnerFactory.createSpinner('Compiling contract..').start();
- const indexTsDestinationPath = path.resolve(destinationPath, 'index.ts');
-
- try {
- this.programFactory([indexTsDestinationPath], {
- module: ModuleKind.ESNext,
- target: ScriptTarget.ESNext,
- skipLibCheck: true,
- declaration: true,
- noImplicitAny: true,
- moduleResolution: ModuleResolutionKind.Bundler,
- outDir: destinationPath,
- }).emit();
-
- spinner.succeed('Compilation completed successfully.');
- this.fileSystemHandler.removeFile(indexTsDestinationPath);
- } catch (error) {
- spinner.fail('Failed to compile contract.');
- throw error;
- }
- }
-}
-
-export class ContractCommandHandler {
- public constructor(
- private readonly spinnerFactory: SpinnerFactory,
- private readonly fileSystemHandler: FileSystemHandler,
- private readonly swaggerParser: typeof SwaggerParser,
- private readonly fileGenerator: ContractFileGenerator,
- private readonly logger: Console,
- private readonly chalker: typeof chalk,
- private readonly apiSpecPathToReadFrom: string
- ) {}
-
- public async handle() {
- try {
- if (!this.fileSystemHandler.exists(this.apiSpecPathToReadFrom)) {
- this.logError(
- 'Could not find Contractual schema that is required for this command. You can provide it with `--spec` argument'
- );
-
- return;
- }
-
- this.logger.log(
- this.chalker.gray(`Contractual schema loaded from ${this.apiSpecPathToReadFrom}`)
- );
-
- const openapiDocument = await this.parseSpec(this.apiSpecPathToReadFrom);
-
- const destinationPath = path.resolve(
- path.dirname(new URL(import.meta.url).pathname),
- '../../..',
- 'contract/contract'
- );
-
- await this.fileGenerator.generateFiles(openapiDocument, destinationPath);
- await this.fileGenerator.compileFiles(destinationPath);
-
- this.logger.log(this.chalker.green('Done'));
- } catch (error) {
- this.logError('Error occurred during contract generation.', error);
- }
- }
-
- private async parseSpec(apiSpecPath: string): Promise {
- const spinner = this.spinnerFactory.createSpinner('Parsing TypeSpec file..').start();
-
- return this.swaggerParser
- .parse(apiSpecPath)
- .then((document) => {
- if (!('openapi' in document)) {
- throw new Error('Invalid OpenAPI document: Missing "openapi" property.');
- }
-
- spinner.succeed('TypeSpec file parsed successfully.');
-
- return document as OpenAPIObject;
- })
- .catch((error) => {
- spinner.fail('Failed to parse TypeSpec file.');
-
- throw error instanceof Error ? new Error(error.message) : error;
- });
- }
-
- private logError(message: string, error?: unknown) {
- this.logger.log(`${this.chalker.red('Error')}: ${message}`);
-
- if (error) {
- this.logger.error('Error details:', error);
- }
- }
-}
diff --git a/packages/generators/contract/src/handlebars-helpers.ts b/packages/generators/contract/src/handlebars-helpers.ts
deleted file mode 100644
index 506c2e3..0000000
--- a/packages/generators/contract/src/handlebars-helpers.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import handlebars from 'handlebars';
-
-const { create } = handlebars;
-
-export function createHandlebars() {
- const instance = create();
-
- instance.registerHelper('ifNotEmptyObj', function (obj, options) {
- if (typeof obj === 'object' && Object.keys(obj).length > 0) {
- return options.fn(this);
- }
-
- return options.inverse(this);
- });
-
- instance.registerHelper('toUpperCase', (input: string) => input.toUpperCase());
-
- instance.registerHelper('ifNotEq', function (a, b, options) {
- if (a !== b) {
- return options.fn(this);
- }
-
- return options.inverse(this);
- });
-
- instance.registerHelper('ifeq', function (a, b, options) {
- if (a === b) {
- return options.fn(this);
- }
-
- return options.inverse(this);
- });
-
- instance.registerHelper('includesType', function (arr, val, options) {
- if (Array.isArray(arr) && arr.length > 0 && arr.some((v) => v.type === val)) {
- return options.fn(this);
- }
-
- return options.inverse(this);
- });
-
- instance.registerHelper('toPlainWords', function (str) {
- return str.replace(/([A-Z])/g, ' $1').toLowerCase();
- });
-
- instance.registerHelper('toDashes', function (str) {
- return str.replace(/([A-Z])/g, '-$1').toLowerCase();
- });
-
- return instance;
-}
diff --git a/packages/generators/contract/src/index.ts b/packages/generators/contract/src/index.ts
deleted file mode 100644
index 4e2ea87..0000000
--- a/packages/generators/contract/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './command.js';
diff --git a/packages/generators/contract/tsconfig.build.json b/packages/generators/contract/tsconfig.build.json
deleted file mode 100644
index 0bc65ae..0000000
--- a/packages/generators/contract/tsconfig.build.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "extends": "../../../tsconfig.build.json",
- "compilerOptions": {
- "rootDir": "src",
- "baseUrl": ".",
- "outDir": "dist",
- "skipLibCheck": true
- },
- "exclude": [
- "dist",
- "index.ts",
- "node_modules",
- "test",
- "**/*.spec.ts",
- "jest.config.ts"
- ]
-}
\ No newline at end of file
diff --git a/packages/generators/contract/tsconfig.json b/packages/generators/contract/tsconfig.json
deleted file mode 100644
index b027bb4..0000000
--- a/packages/generators/contract/tsconfig.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../tsconfig.json"
-}
\ No newline at end of file
diff --git a/packages/generators/diff/.eslintrc b/packages/generators/diff/.eslintrc
deleted file mode 100644
index 3280263..0000000
--- a/packages/generators/diff/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../.eslintrc"
-}
\ No newline at end of file
diff --git a/packages/generators/diff/index.ts b/packages/generators/diff/index.ts
deleted file mode 100644
index 8420b10..0000000
--- a/packages/generators/diff/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './src';
diff --git a/packages/generators/diff/package.json b/packages/generators/diff/package.json
deleted file mode 100644
index f09cb42..0000000
--- a/packages/generators/diff/package.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "name": "@contractual/generators.diff",
- "private": false,
- "version": "0.0.0",
- "license": "MIT",
- "type": "module",
- "module": "dist/index.js",
- "main": "dist/index.js",
- "repository": {
- "type": "git",
- "url": "https://github.com/contractual-dev/contractual.git",
- "directory": "packages/generators/diff"
- },
- "exports": {
- ".": {
- "import": "./dist/index.js",
- "require": "./dist/index.js"
- }
- },
- "homepage": "https://contractual.dev",
- "bugs": {
- "url": "https://github.com/contractual-dev/contractual/issues"
- },
- "contributors": [
- {
- "name": "Omer Morad",
- "email": "omer.moradd@gmail.com"
- }
- ],
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/contractual-dev"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/contractual-dev"
- }
- ],
- "engines": {
- "node": ">=18.12.0"
- },
- "scripts": {
- "prebuild": "pnpm rimraf dist",
- "build": "tsc -p tsconfig.build.json",
- "test": "pnpm vitest run --watch",
- "build:watch": "tsc -p tsconfig.build.json --watch",
- "lint": "eslint '{src,test}/**/*.ts'"
- },
- "files": [
- "dist",
- "README.md"
- ],
- "publishConfig": {
- "access": "public",
- "provenance": true
- },
- "dependencies": {
- "chalk": "^5.4.1",
- "openapi-diff": "^0.23.7",
- "openapi-types": "^12.1.3",
- "semver": "^7.6.3",
- "table": "^6.9.0"
- },
- "devDependencies": {
- "@types/semver": "^7.5.8",
- "@vitest/coverage-c8": "^0.33.0",
- "typescript": "~5.7.2",
- "vitest": "^3.0.3"
- }
-}
diff --git a/packages/generators/diff/src/diff-highlighter.ts b/packages/generators/diff/src/diff-highlighter.ts
deleted file mode 100644
index 58a281b..0000000
--- a/packages/generators/diff/src/diff-highlighter.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import chalk from 'chalk';
-import { table } from 'table';
-import type OpenApiDiff from 'openapi-diff';
-import { type DiffOutcome } from 'openapi-diff';
-import type { TableUserConfig } from 'table/dist/src/types/api.js';
-
-async function printOpenApiDiff(diffOutcome: DiffOutcome) {
- try {
- if ('breakingDifferencesFound' in diffOutcome && diffOutcome.breakingDifferencesFound) {
- console.log(chalk.red.bold('\nBreaking Differences Found:\n'));
- console.log(formatDiffs(diffOutcome.breakingDifferences, chalk.red));
- }
-
- if (diffOutcome.nonBreakingDifferences.length > 0) {
- console.log(chalk.green.bold('\nNon-Breaking Differences:\n'));
- console.log(formatDiffs(diffOutcome.nonBreakingDifferences, chalk.green));
- }
-
- if (diffOutcome.unclassifiedDifferences.length > 0) {
- console.log(chalk.yellow.bold('\nUnclassified Differences:\n'));
- console.log(formatDiffs(diffOutcome.unclassifiedDifferences, chalk.yellow));
- }
-
- if (
- !('breakingDifferencesFound' in diffOutcome) ||
- (!diffOutcome.breakingDifferencesFound &&
- diffOutcome.nonBreakingDifferences.length === 0 &&
- diffOutcome.unclassifiedDifferences.length === 0)
- ) {
- console.log(
- chalk.green.bold('\nNo Differences Found! Specifications are identical or compatible.\n')
- );
- }
- } catch (error) {
- console.error(chalk.red.bold('\nError performing diff:\n'));
- console.error(error);
- }
-}
-
-function formatDiffs(
- diffs: OpenApiDiff.DiffResult[],
- colorFn: (text: string) => string
-): string {
- const formattedDiffs = diffs.map((diff) => [
- colorFn(diff.code),
- colorFn(diff.entity),
- chalk.bold(diff.action === 'add' ? 'β Add' : 'β Remove'),
- diff.sourceSpecEntityDetails.map((d) => `${d.location}`).join(', '),
- diff.destinationSpecEntityDetails.map((d) => `${d.location}`).join(', '),
- ]);
-
- const tableConfig: TableUserConfig = {
- columns: {
- 0: { alignment: 'left', width: 20 },
- 1: { alignment: 'left', width: 20 },
- 2: { alignment: 'center', width: 10 },
- 3: { alignment: 'left', width: 30 },
- 4: { alignment: 'left', width: 30 },
- },
- };
-
- return table(
- [
- [
- chalk.underline.bold('Code'),
- chalk.underline.bold('Entity'),
- chalk.underline.bold('Action'),
- chalk.underline.bold('Source Location'),
- chalk.underline.bold('Destination Location'),
- ],
- ...formattedDiffs,
- ],
- tableConfig
- );
-}
-
-export { printOpenApiDiff };
diff --git a/packages/generators/diff/src/generator.spec.ts b/packages/generators/diff/src/generator.spec.ts
deleted file mode 100644
index 324ad41..0000000
--- a/packages/generators/diff/src/generator.spec.ts
+++ /dev/null
@@ -1,886 +0,0 @@
-import { afterAll, beforeAll, describe, expect, it } from 'vitest';
-import * as fs from 'node:fs';
-import * as path from 'node:path';
-import { diffSpecs } from './generator';
-
-const dummyOpenApiSpecBreaking = `
-openapi: 3.0.0
-info:
- title: Petstore API
- description: A simple API for managing a pet store.
- version: 0.0.0
-tags: []
-paths:
- /pet:
- post:
- operationId: addPet
- description: Add a new pet to the store.
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreatePetResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/AddPetBody'
- /pet/{petId}:
- get:
- operationId: getPetById
- description: Retrieve a pet by ID.
- parameters:
- - name: petId
- in: path
- required: true
- schema:
- type: integer
- format: int32
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetPetResponse'
- /store/order:
- post:
- operationId: placeOrder
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateOrderResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PlaceOrderBody'
- /store/order/{orderId}:
- get:
- operationId: getOrderById
- description: Retrieve an order by ID.
- parameters:
- - name: orderId
- in: path
- required: true
- schema:
- type: integer
- format: int32
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetOrderResponse'
- /user:
- post:
- operationId: createUser
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateUserResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateUserBody'
- /user/{username}:
- get:
- operationId: getUserByUsername
- description: Retrieve a user by username.
- parameters:
- - name: username
- in: path
- required: true
- schema:
- type: string
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetUserResponse'
-components:
- schemas:
- AddPetBody:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- description: Name of the pet.
- category:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- tags:
- type: array
- items:
- type: string
- description: List of tags associated with the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- description: Request body for adding a new pet.
- ApiResponse:
- type: object
- required:
- - code
- - type
- - message
- properties:
- code:
- type: integer
- format: int32
- description: Status code of the response.
- type:
- type: string
- description: The type of response (e.g., success, error).
- message:
- type: string
- description: Detailed message about the response.
- description: Represents a standard API response for messages or errors.
- CreateOrderResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created order.
- description: Response for creating an order.
- CreatePetResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created pet.
- description: Response for creating a pet.
- CreateUserBody:
- type: object
- required:
- - username
- - firstName
- - lastName
- - email
- - password
- - phone
- properties:
- username:
- type: string
- description: Username of the user.
- firstName:
- type: string
- description: First name of the user.
- lastName:
- type: string
- description: Last name of the user.
- email:
- type: string
- description: Email address of the user.
- password:
- type: string
- description: Password for the user account.
- phone:
- type: string
- description: Phone number of the user.
- userStatus:
- type: integer
- format: int32
- description: User status (e.g., 1 for active, 0 for inactive).
- description: Create a new user.
- CreateUserResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created user.
- description: Response for creating a user.
- GetOrderResponse:
- type: object
- required:
- - id
- - petId
- - status
- - quantity
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the order.
- petId:
- type: integer
- format: int32
- description: Identifier of the pet associated with the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- description: Response for retrieving an order.
- GetPetResponse:
- type: object
- required:
- - id
- - name
- - status
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the pet.
- name:
- type: string
- description: Name of the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- description: Response for retrieving a pet.
- GetUserResponse:
- type: object
- required:
- - id
- - username
- - email
- - phone
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the user.
- username:
- type: string
- description: Username associated with the user.
- email:
- type: string
- description: Email address of the user.
- phone:
- type: string
- description: Phone number of the user.
- description: Response for retrieving a user.
- Order:
- type: object
- required:
- - id
- - petId
- - quantity
- - shipDate
- - status
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the order.
- petId:
- type: integer
- format: int32
- description: ID of the pet being ordered.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- shipDate:
- type: string
- description: Shipping date for the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- complete:
- type: boolean
- description: Indicates whether the order is complete.
- description: Represents an order for purchasing a pet.
- Pet:
- type: object
- required:
- - id
- - name
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the pet.
- name:
- type: string
- description: Name of the pet.
- category:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- tags:
- type: array
- items:
- type: string
- description: List of tags associated with the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- description: Represents a pet in the store.
- PlaceOrderBody:
- type: object
- required:
- - petId
- - quantity
- - shipDate
- - status
- properties:
- petId:
- type: integer
- format: int32
- description: ID of the pet being ordered.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- shipDate:
- type: string
- description: Shipping date for the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- complete:
- type: boolean
- description: Indicates whether the order is complete.
- description: Place an order for a pet.
- User:
- type: object
- required:
- - id
- - username
- - firstName
- - lastName
- - email
- - password
- - phone
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the user.
- username:
- type: string
- description: Username of the user.
- firstName:
- type: string
- description: First name of the user.
- lastName:
- type: string
- description: Last name of the user.
- email:
- type: string
- description: Email address of the user.
- password:
- type: string
- description: Password for the user account.
- phone:
- type: string
- description: Phone number of the user.
- userStatus:
- type: integer
- format: int32
- description: User status (e.g., 1 for active, 0 for inactive).
- description: Represents a user of the pet store.
-`;
-
-const dummyOpenApiSpecMinor = `
-openapi: 3.0.0
-info:
- title: Petstore API
- description: A simple API for managing a pet store.
- version: 0.0.0
-tags: []
-paths:
- /pet:
- post:
- operationId: addPet
- description: Add a new pet to the store.
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreatePetResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/AddPetBody'
- /pet/{petId}:
- get:
- operationId: getPetById
- description: Retrieve a pet by ID.
- parameters:
- - name: petId
- in: path
- required: true
- schema:
- type: integer
- format: int32
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetPetResponse'
- /store/order:
- post:
- operationId: placeOrder
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateOrderResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PlaceOrderBody'
- /store/order/{orderId}:
- get:
- operationId: getOrderById
- description: Retrieve an order by ID.
- parameters:
- - name: orderId
- in: path
- required: true
- schema:
- type: integer
- format: int32
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetOrderResponse'
- /user:
- post:
- operationId: createUser
- parameters: []
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateUserResponse'
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/CreateUserBody'
- /user/{username}:
- get:
- operationId: getUserByUsername
- description: Retrieve a user by username.
- parameters:
- - name: username
- in: path
- required: true
- schema:
- type: string
- responses:
- '200':
- description: The request has succeeded.
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/GetUserResponse'
-components:
- schemas:
- AddPetBody:
- type: object
- required:
- - name
- properties:
- name:
- type: string
- description: Name of the pet.
- category:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- tags:
- type: array
- items:
- type: string
- description: List of tags associated with the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- description: Request body for adding a new pet.
- ApiResponse:
- type: object
- required:
- - code
- - type
- - message
- properties:
- code:
- type: integer
- format: int32
- description: Status code of the response.
- type:
- type: string
- description: The type of response (e.g., success, error).
- message:
- type: string
- description: Detailed message about the response.
- description: Represents a standard API response for messages or errors.
- CreateOrderResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created order.
- description: Response for creating an order.
- CreatePetResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created pet.
- description: Response for creating a pet.
- CreateUserBody:
- type: object
- required:
- - username
- - firstName
- - lastName
- - email
- - password
- - phone
- properties:
- username:
- type: string
- description: Username of the user.
- firstName:
- type: string
- description: First name of the user.
- lastName:
- type: string
- description: Last name of the user.
- email:
- type: string
- description: Email address of the user.
- password:
- type: string
- description: Password for the user account.
- phone:
- type: string
- description: Phone number of the user.
- userStatus:
- type: integer
- format: int32
- description: User status (e.g., 1 for active, 0 for inactive).
- description: Create a new user.
- CreateUserResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the created user.
- description: Response for creating a user.
- GetOrderResponse:
- type: object
- required:
- - id
- - petId
- - status
- - quantity
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the order.
- petId:
- type: integer
- format: int32
- description: Identifier of the pet associated with the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- description: Response for retrieving an order.
- GetPetResponse:
- type: object
- required:
- - id
- - name
- - status
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the pet.
- name:
- type: string
- description: Name of the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- category:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- nickname:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- description: Response for retrieving a pet.
- GetUserResponse:
- type: object
- required:
- - id
- - username
- - email
- - phone
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier of the user.
- username:
- type: string
- description: Username associated with the user.
- email:
- type: string
- description: Email address of the user.
- phone:
- type: string
- description: Phone number of the user.
- description: Response for retrieving a user.
- Order:
- type: object
- required:
- - id
- - petId
- - quantity
- - shipDate
- - status
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the order.
- petId:
- type: integer
- format: int32
- description: ID of the pet being ordered.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- shipDate:
- type: string
- description: Shipping date for the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- complete:
- type: boolean
- description: Indicates whether the order is complete.
- description: Represents an order for purchasing a pet.
- Pet:
- type: object
- required:
- - id
- - name
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the pet.
- name:
- type: string
- description: Name of the pet.
- category:
- type: string
- description: Category of the pet (e.g., dog, cat, bird).
- tags:
- type: array
- items:
- type: string
- description: List of tags associated with the pet.
- status:
- type: string
- enum:
- - available
- - pending
- - sold
- description: The current status of the pet in the store.
- description: Represents a pet in the store.
- PlaceOrderBody:
- type: object
- required:
- - petId
- - quantity
- - shipDate
- - status
- properties:
- petId:
- type: integer
- format: int32
- description: ID of the pet being ordered.
- quantity:
- type: integer
- format: int32
- description: Quantity of pets ordered.
- shipDate:
- type: string
- description: Shipping date for the order.
- status:
- type: string
- enum:
- - placed
- - approved
- - delivered
- description: The current status of the order.
- complete:
- type: boolean
- description: Indicates whether the order is complete.
- description: Place an order for a pet.
- User:
- type: object
- required:
- - id
- - username
- - firstName
- - lastName
- - email
- - password
- - phone
- properties:
- id:
- type: integer
- format: int32
- description: Unique identifier for the user.
- username:
- type: string
- description: Username of the user.
- firstName:
- type: string
- description: First name of the user.
- lastName:
- type: string
- description: Last name of the user.
- email:
- type: string
- description: Email address of the user.
- password:
- type: string
- description: Password for the user account.
- phone:
- type: string
- description: Phone number of the user.
- userStatus:
- type: integer
- format: int32
- description: User status (e.g., 1 for active, 0 for inactive).
- description: Represents a user of the pet store.
-`;
-
-describe('diffSpecs', () => {
- const tempDir = path.resolve(new URL('.', import.meta.url).pathname, 'temp');
- const spec1Path = path.join(tempDir, 'spec1.yaml');
- const spec2Path = path.join(tempDir, 'spec2.yaml');
-
- beforeAll(() => {
- if (!fs.existsSync(tempDir)) {
- fs.mkdirSync(tempDir);
- }
- });
-
- afterAll(() => {
- fs.rmSync(tempDir, { force: true, recursive: true });
- });
-
- it.only('should detect no changes between identical specs', async () => {
- fs.writeFileSync(spec1Path, dummyOpenApiSpecBreaking);
- fs.writeFileSync(spec2Path, dummyOpenApiSpecMinor);
- const result = await diffSpecs(spec2Path, spec1Path);
- expect(result.version).toBe('minor');
- expect(result.diff).toEqual([]);
- });
-});
diff --git a/packages/generators/diff/src/generator.ts b/packages/generators/diff/src/generator.ts
deleted file mode 100644
index 97635f7..0000000
--- a/packages/generators/diff/src/generator.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as fs from 'node:fs';
-import openapiDiff, { type DiffOutcome } from 'openapi-diff';
-
-interface DiffResult {
- version: 'minor' | 'major' | 'patch' | 'unchanged';
- diff: DiffOutcome | null;
-}
-
-export async function diffSpecs(
- destinationSpecPath: string,
- sourceSpecPath: string
-): Promise {
- const diff = await openapiDiff.diffSpecs({
- destinationSpec: {
- content: fs.readFileSync(destinationSpecPath, 'utf-8'),
- location: destinationSpecPath,
- format: 'openapi3',
- },
- sourceSpec: {
- content: fs.readFileSync(sourceSpecPath, 'utf-8'),
- location: sourceSpecPath,
- format: 'openapi3',
- },
- });
-
- if (diff.breakingDifferencesFound) {
- return { version: 'major', diff: diff };
- }
-
- if (diff.unclassifiedDifferences.length === 0 && diff.nonBreakingDifferences.length === 0) {
- return { version: 'unchanged', diff: null };
- }
-
- return { version: 'minor', diff: diff };
-}
diff --git a/packages/generators/diff/src/index.ts b/packages/generators/diff/src/index.ts
deleted file mode 100644
index ff776ac..0000000
--- a/packages/generators/diff/src/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './generator.js';
-export * from './diff-highlighter.js';
diff --git a/packages/generators/diff/tsconfig.build.json b/packages/generators/diff/tsconfig.build.json
deleted file mode 100644
index 0bc65ae..0000000
--- a/packages/generators/diff/tsconfig.build.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "extends": "../../../tsconfig.build.json",
- "compilerOptions": {
- "rootDir": "src",
- "baseUrl": ".",
- "outDir": "dist",
- "skipLibCheck": true
- },
- "exclude": [
- "dist",
- "index.ts",
- "node_modules",
- "test",
- "**/*.spec.ts",
- "jest.config.ts"
- ]
-}
\ No newline at end of file
diff --git a/packages/generators/diff/tsconfig.json b/packages/generators/diff/tsconfig.json
deleted file mode 100644
index b027bb4..0000000
--- a/packages/generators/diff/tsconfig.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../tsconfig.json"
-}
\ No newline at end of file
diff --git a/packages/generators/spec/.eslintrc b/packages/generators/spec/.eslintrc
deleted file mode 100644
index 3280263..0000000
--- a/packages/generators/spec/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../.eslintrc"
-}
\ No newline at end of file
diff --git a/packages/generators/spec/index.ts b/packages/generators/spec/index.ts
deleted file mode 100644
index 8420b10..0000000
--- a/packages/generators/spec/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './src';
diff --git a/packages/generators/spec/package.json b/packages/generators/spec/package.json
deleted file mode 100644
index 825caca..0000000
--- a/packages/generators/spec/package.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "name": "@contractual/generators.spec",
- "private": false,
- "version": "0.0.0",
- "license": "MIT",
- "type": "module",
- "module": "dist/index.js",
- "main": "dist/index.js",
- "repository": {
- "type": "git",
- "url": "https://github.com/contractual-dev/contractual.git",
- "directory": "packages/generators/spec"
- },
- "exports": {
- ".": {
- "import": "./dist/index.js",
- "require": "./dist/index.js"
- }
- },
- "homepage": "https://contractual.dev",
- "bugs": {
- "url": "https://github.com/contractual-dev/contractual/issues"
- },
- "contributors": [
- {
- "name": "Omer Morad",
- "email": "omer.moradd@gmail.com"
- }
- ],
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/contractual-dev"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/contractual-dev"
- }
- ],
- "engines": {
- "node": ">=18.12.0"
- },
- "scripts": {
- "prebuild": "pnpm rimraf dist",
- "build": "tsc -p tsconfig.build.json",
- "build:watch": "tsc -p tsconfig.build.json --watch",
- "tester": "jest --coverage --verbose",
- "lint": "eslint '{src,test}/**/*.ts'"
- },
- "files": [
- "dist",
- "README.md"
- ],
- "publishConfig": {
- "access": "public",
- "provenance": true
- },
- "dependencies": {
- "@contractual/generators.diff": "workspace:*",
- "@typespec/compiler": "^0.63.0",
- "@typespec/http": "^0.63.0",
- "@typespec/openapi": "^0.63.0",
- "@typespec/openapi3": "^0.63.0",
- "@typespec/rest": "^0.63.1",
- "@typespec/versioning": "^0.63.0",
- "semver": "^7.6.3",
- "yaml": "^2.7.0"
- },
- "devDependencies": {
- "@types/semver": "^7.5.8",
- "chalk": "^5.4.1",
- "inquirer": "^12.3.2",
- "openapi-types": "^12.1.3",
- "ora": "^8.1.1",
- "typescript": "~5.7.2"
- },
- "peerDependencies": {
- "typescript": ">=5.x"
- }
-}
diff --git a/packages/generators/spec/src/generator.ts b/packages/generators/spec/src/generator.ts
deleted file mode 100644
index 415c74a..0000000
--- a/packages/generators/spec/src/generator.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-import { compile, logDiagnostics, NodeHost } from '@typespec/compiler';
-import * as fs from 'node:fs';
-import * as path from 'node:path';
-import * as process from 'node:process';
-import { parse, stringify } from 'yaml';
-import { inc } from 'semver';
-import type inquirer from 'inquirer';
-import ora from 'ora';
-import chalk from 'chalk';
-import { diffSpecs, printOpenApiDiff } from '@contractual/generators.diff';
-
-export function initializePaths() {
- const rootPath = path.resolve(process.cwd(), 'contractual');
- const configFilePath = path.resolve(rootPath, 'api-lock.yaml');
- const snapshotsPath = path.resolve(rootPath, 'specs');
- const currentPath = path.resolve(path.dirname(new URL(import.meta.url).pathname));
- const specPath = path.resolve(rootPath, 'api.tsp');
- const tempSpecPath = path.resolve(currentPath, '@typespec', 'openapi3', 'openapi.yaml');
-
- return { rootPath, configFilePath, snapshotsPath, currentPath, specPath, tempSpecPath };
-}
-
-function checkFileExists(filePath: string, errorMessage: string): boolean {
- if (!fs.existsSync(filePath)) {
- console.error(errorMessage, filePath);
- return false;
- }
-
- return true;
-}
-
-async function compileSpecification(specPath: string, outputPath: string) {
- const program = await compile(NodeHost, specPath, {
- emit: ['@typespec/openapi3'],
- additionalImports: ['@typespec/openapi', '@typespec/openapi3', '@typespec/http'],
- outputDir: outputPath,
- ignoreDeprecated: true,
- warningAsError: false,
- });
-
- if (program.hasError()) {
- logDiagnostics(
- program.diagnostics.filter(({ severity }) => severity === 'error'),
- NodeHost.logSink
- );
-
- return null;
- }
-
- return program;
-}
-
-async function checkSpecificationDifferences(
- tempSpecPath: string,
- snapshotsPath: string,
- version: string
-) {
- return diffSpecs(tempSpecPath, path.resolve(snapshotsPath, `openapi-v${version}.yaml`));
-}
-
-function updateVersionAndSnapshot(
- configPath: string,
- snapshotsPath: string,
- tempSpecPath: string,
- currentVersion: string
-) {
- const newVersion = inc(currentVersion, 'minor');
- const newConfigContent = stringify({ version: { latest: newVersion } });
-
- fs.writeFileSync(configPath, newConfigContent);
- fs.copyFileSync(tempSpecPath, path.resolve(snapshotsPath, `openapi-v${newVersion}.yaml`));
-}
-
-export function getLatestVersion(configPath: string) {
- const configContent = parse(fs.readFileSync(configPath, 'utf-8'));
- return configContent.version.latest;
-}
-
-export async function generateSpecification(inquirerDep: typeof inquirer) {
- const paths = initializePaths();
-
- if (!checkFileExists(paths.rootPath, `'contractual' directory not found`)) {
- return;
- }
-
- if (!fs.existsSync(paths.snapshotsPath)) {
- fs.mkdirSync(paths.snapshotsPath);
- }
-
- if (!checkFileExists(paths.specPath, 'specification file not found')) {
- process.exit(1);
- }
-
- const latest = getLatestVersion(paths.configFilePath);
-
- console.log(chalk.gray(`Latest version is ${latest}`));
-
- const spinner = ora('Compiling TypeSpec API specification..').start();
-
- const program = await compileSpecification(paths.specPath, paths.currentPath);
-
- if (!program) {
- spinner.fail('Compilation failed due to compilation errors');
- return;
- }
-
- if (!checkFileExists(paths.tempSpecPath, 'openapi.yaml not found')) {
- spinner.fail('Compilation failed due to missing temp openapi.yaml');
- return;
- }
-
- spinner.succeed('TypeSpec API specification compiled successfully');
-
- if (latest === 'unversioned') {
- const { initialVersion } = await inquirerDep.prompt([
- {
- type: 'input',
- name: 'initialVersion',
- message: 'Please provide the initial version (e.g., 1.0.0):',
- default: '1.0.0',
- validate: (input) =>
- /^\d+\.\d+\.\d+$/.test(input) ||
- 'Invalid version format. Please use semantic versioning format (e.g., 1.0.0).',
- },
- ]);
-
- const updateSpinner = ora('Creating new version..').start();
-
- const destinationPath = path.resolve(paths.snapshotsPath, `openapi-v${initialVersion}.yaml`);
-
- fs.copyFileSync(paths.tempSpecPath, destinationPath);
-
- updateSpinner.info(`New version ${initialVersion} created successfully`);
-
- const newConfigContent = stringify({ version: { latest: initialVersion } });
-
- fs.writeFileSync(paths.configFilePath, newConfigContent);
-
- updateSpinner.info(`Updated to new version: ${initialVersion}`);
-
- updateSpinner.succeed('Specification generated successfully');
-
- return;
- }
-
- const diffSpinner = ora('Checking for API diff..').start();
-
- const differences = await checkSpecificationDifferences(
- paths.tempSpecPath,
- paths.snapshotsPath,
- latest
- );
-
- if (differences.version === 'unchanged') {
- diffSpinner.info('No differences found. Specifications are identical or compatible.');
- return;
- }
-
- diffSpinner.info('Differences found');
-
- await printOpenApiDiff(differences.diff!);
-
- const { confirmUpdate } = await inquirerDep.prompt([
- {
- type: 'confirm',
- name: 'confirmUpdate',
- message: 'Do you want to update the API version?',
- default: true,
- },
- ]);
-
- if (!confirmUpdate) {
- diffSpinner.info('API version not updated');
- return;
- }
-
- diffSpinner.start('Updating API version..');
-
- updateVersionAndSnapshot(paths.configFilePath, paths.snapshotsPath, paths.tempSpecPath, latest);
-
- diffSpinner.succeed('API version updated successfully');
-}
diff --git a/packages/generators/spec/src/index.ts b/packages/generators/spec/src/index.ts
deleted file mode 100644
index 9f33372..0000000
--- a/packages/generators/spec/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './generator.js';
diff --git a/packages/generators/spec/tsconfig.build.json b/packages/generators/spec/tsconfig.build.json
deleted file mode 100644
index 0bc65ae..0000000
--- a/packages/generators/spec/tsconfig.build.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "extends": "../../../tsconfig.build.json",
- "compilerOptions": {
- "rootDir": "src",
- "baseUrl": ".",
- "outDir": "dist",
- "skipLibCheck": true
- },
- "exclude": [
- "dist",
- "index.ts",
- "node_modules",
- "test",
- "**/*.spec.ts",
- "jest.config.ts"
- ]
-}
\ No newline at end of file
diff --git a/packages/generators/spec/tsconfig.json b/packages/generators/spec/tsconfig.json
deleted file mode 100644
index b027bb4..0000000
--- a/packages/generators/spec/tsconfig.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "../../../tsconfig.json"
-}
\ No newline at end of file
diff --git a/packages/governance/differs/index.ts b/packages/governance/differs/index.ts
new file mode 100644
index 0000000..d41479f
--- /dev/null
+++ b/packages/governance/differs/index.ts
@@ -0,0 +1,12 @@
+/**
+ * Differs
+ *
+ * Contract differ implementations for detecting structural changes
+ * between two versions of a contract specification.
+ *
+ * All differs are pure Node.js - no binary dependencies.
+ */
+
+export { diffOpenApi, diffOpenApiObjects, resolveOpenApiSpec } from '@contractual/differs.openapi';
+
+export { diffJsonSchema } from './json-schema/index.js';
diff --git a/packages/governance/differs/json-schema/index.ts b/packages/governance/differs/json-schema/index.ts
new file mode 100644
index 0000000..8fc70fa
--- /dev/null
+++ b/packages/governance/differs/json-schema/index.ts
@@ -0,0 +1,9 @@
+/**
+ * JSON Schema Differ
+ *
+ * Re-exports from @contractual/differs.json-schema package.
+ * This module provides JSON Schema structural diffing capabilities.
+ */
+
+// Re-export everything from the json-schema-differ package
+export * from '@contractual/differs.json-schema';
diff --git a/packages/governance/index.ts b/packages/governance/index.ts
new file mode 100644
index 0000000..5014918
--- /dev/null
+++ b/packages/governance/index.ts
@@ -0,0 +1,106 @@
+/**
+ * Governance Engines
+ *
+ * Central module for all linting and diffing capabilities.
+ * Registers all built-in engines with the registry at import time.
+ */
+
+import { registerLinter, registerDiffer } from './registry.js';
+import { lintOpenAPI } from './linters/openapi-redocly.js';
+import { lintJsonSchema } from './linters/json-schema-ajv.js';
+import { diffOpenApi } from '@contractual/differs.openapi';
+import { diffJsonSchema } from '@contractual/differs.json-schema';
+
+// Re-export registry functions
+export {
+ registerLinter,
+ registerDiffer,
+ getLinter,
+ getDiffer,
+ hasLinter,
+ hasDiffer,
+ getRegisteredLinterTypes,
+ getRegisteredDifferTypes,
+} from './registry.js';
+
+// Re-export types from @contractual/types
+export type {
+ Change,
+ ChangeSeverity,
+ DiffResult,
+ DiffSummary,
+ SuggestedBump,
+ LintResult,
+ LintIssue,
+ LintSeverity,
+ LintFn,
+ DiffFn,
+ ContractType,
+ RawChange,
+ ChangeType,
+} from '@contractual/types';
+
+// Re-export linters
+export { lintOpenAPI } from './linters/openapi-redocly.js';
+export { lintJsonSchema } from './linters/json-schema-ajv.js';
+
+// Re-export OpenAPI differ
+export { diffOpenApi, diffOpenApiObjects, resolveOpenApiSpec } from '@contractual/differs.openapi';
+
+// Re-export everything from JSON Schema differ package
+export {
+ diffJsonSchema,
+ diffJsonSchemaObjects,
+ compareSchemas,
+ checkCompatibility,
+ classify,
+ classifyPropertyAdded,
+ classifyAll,
+ CLASSIFICATION_SETS,
+ resolveRefs,
+ hasUnresolvedRefs,
+ extractRefs,
+ validateRefs,
+ walk,
+ formatChangeMessage,
+} from '@contractual/differs.json-schema';
+
+export type {
+ CompareResult,
+ CompareOptions,
+ StrandsTrace,
+ StrandsCompatibility,
+ StrandsVersion,
+ SemanticVersion,
+ JsonSchemaDraft,
+ ResolvedSchema,
+ ResolveResult,
+} from '@contractual/differs.json-schema';
+
+// Re-export runner for custom commands
+export { executeCustomCommand, parseCustomLintOutput, parseCustomDiffOutput } from './runner.js';
+
+/**
+ * Register all built-in governance engines
+ *
+ * Call this function at CLI startup to make all engines available
+ * through the registry.
+ */
+export function registerAllEngines(): void {
+ // Register linters
+ registerLinter('openapi', lintOpenAPI);
+ registerLinter('json-schema', lintJsonSchema);
+
+ // Register differs
+ registerDiffer('openapi', diffOpenApi);
+ registerDiffer('json-schema', diffJsonSchema);
+
+ // Phase 2:
+ // registerLinter('asyncapi', lintAsyncAPI);
+ // registerLinter('odcs', lintODCS);
+ // registerDiffer('asyncapi', diffAsyncAPI);
+ // registerDiffer('odcs', diffODCS);
+}
+
+// Auto-register on import
+registerAllEngines();
diff --git a/packages/governance/linters/index.ts b/packages/governance/linters/index.ts
new file mode 100644
index 0000000..42dc1a1
--- /dev/null
+++ b/packages/governance/linters/index.ts
@@ -0,0 +1,20 @@
+/**
+ * Linters - Export all linter implementations
+ */
+
+export { lintOpenAPI } from './openapi-redocly.js';
+export { lintJsonSchema, lintJsonSchemaObject } from './json-schema-ajv.js';
+export type { JsonSchemaLintOptions } from './json-schema-ajv.js';
+
+// JSON Schema lint rules (for programmatic access)
+export {
+ runLintRules,
+ getAvailableRules,
+ getRuleDescription,
+ LINT_RULES,
+} from './json-schema-rules.js';
+export type { LintRule, SchemaNode } from './json-schema-rules.js';
+
+// Phase 2:
+// export { lintAsyncAPI } from './asyncapi-parser.js';
+// export { lintODCS } from './odcs-ajv.js';
diff --git a/packages/governance/linters/json-schema-ajv.ts b/packages/governance/linters/json-schema-ajv.ts
new file mode 100644
index 0000000..defa954
--- /dev/null
+++ b/packages/governance/linters/json-schema-ajv.ts
@@ -0,0 +1,189 @@
+/**
+ * JSON Schema Linter using ajv + custom rules
+ *
+ * Two-phase linting:
+ * 1. Meta-validation: Validates that the schema is itself valid JSON Schema (ajv)
+ * 2. Style rules: Checks for best practices, anti-patterns, and quality (custom rules)
+ *
+ * @see https://github.com/sourcemeta/jsonschema
+ * @see https://github.com/orgs/json-schema-org/discussions/323
+ */
+
+import { readFile } from 'node:fs/promises';
+import Ajv from 'ajv';
+import addFormats from 'ajv-formats';
+import type { LintResult, LintIssue, LintOptions } from '@contractual/types';
+import { runLintRules } from './json-schema-rules.js';
+import type { SchemaNode } from './json-schema-rules.js';
+
+const AjvConstructor = Ajv.default ?? Ajv;
+const addFormatsFunc = addFormats.default ?? addFormats;
+
+/**
+ * Options for JSON Schema linting (extends base LintOptions)
+ */
+export interface JsonSchemaLintOptions extends LintOptions {
+ /** Rules to enable (if not specified, all rules are enabled) */
+ enabledRules?: Set;
+ /** Rules to disable */
+ disabledRules?: Set;
+ /** Skip meta-validation (ajv) */
+ skipMetaValidation?: boolean;
+ /** Skip style rules */
+ skipStyleRules?: boolean;
+}
+
+/**
+ * Lint a JSON Schema using ajv meta-validation and custom style rules
+ *
+ * @param specPath - Path to the JSON Schema file
+ * @param options - Linting options
+ * @returns Lint result with errors and warnings
+ */
+export async function lintJsonSchema(
+ specPath: string,
+ options: JsonSchemaLintOptions = {}
+): Promise {
+ const errors: LintIssue[] = [];
+ const warnings: LintIssue[] = [];
+
+ let schema: SchemaNode;
+
+ try {
+ const content = await readFile(specPath, 'utf-8');
+ schema = JSON.parse(content) as SchemaNode;
+ } catch (error: unknown) {
+ const message = error instanceof Error ? error.message : 'Unknown error reading schema';
+
+ errors.push({
+ path: '/',
+ message: `Failed to read or parse schema: ${message}`,
+ rule: 'parse-error',
+ severity: 'error',
+ });
+
+ return { contract: '', specPath, errors, warnings };
+ }
+
+ // Phase 1: Meta-validation using ajv
+ if (!options.skipMetaValidation) {
+ const ajv = new AjvConstructor({
+ allErrors: true,
+ strict: false,
+ validateSchema: true,
+ });
+ addFormatsFunc(ajv);
+
+ const valid = ajv.validateSchema(schema);
+
+ if (!valid && ajv.errors) {
+ for (const err of ajv.errors) {
+ errors.push({
+ path: err.instancePath || '/',
+ message: `${err.keyword}: ${err.message}`,
+ rule: `meta:${err.keyword}`,
+ severity: 'error',
+ });
+ }
+ }
+ }
+
+ // Phase 2: Style rules
+ if (!options.skipStyleRules) {
+ const styleIssues = runLintRules(schema, options.enabledRules, options.disabledRules);
+
+ // Partition into errors and warnings
+ for (const issue of styleIssues) {
+ if (issue.severity === 'error') {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ }
+
+ // Additional meta-level warnings
+
+ // Warn about unknown $schema versions
+ if (schema.$schema && typeof schema.$schema === 'string') {
+ const schemaUri = schema.$schema;
+ const supportedDrafts = ['draft-04', 'draft-06', 'draft-07', 'draft/2019-09', 'draft/2020-12'];
+ const isKnown = supportedDrafts.some(
+ (draft) => schemaUri.includes(draft) || schemaUri.includes(draft.replace('draft-', 'draft/'))
+ );
+
+ if (!isKnown && !schemaUri.includes('json-schema.org')) {
+ warnings.push({
+ path: '/$schema',
+ message: `Unknown schema draft: ${schemaUri}. Validation may be incomplete.`,
+ rule: 'unknown-draft',
+ severity: 'warning',
+ });
+ }
+ }
+
+ return {
+ contract: '',
+ specPath,
+ errors,
+ warnings,
+ };
+}
+
+/**
+ * Lint a JSON Schema object directly (no file I/O)
+ *
+ * @param schema - JSON Schema object
+ * @param options - Linting options
+ * @returns Lint result with errors and warnings
+ */
+export async function lintJsonSchemaObject(
+ schema: SchemaNode,
+ options: JsonSchemaLintOptions = {}
+): Promise {
+ const errors: LintIssue[] = [];
+ const warnings: LintIssue[] = [];
+
+ // Phase 1: Meta-validation using ajv
+ if (!options.skipMetaValidation) {
+ const ajv = new AjvConstructor({
+ allErrors: true,
+ strict: false,
+ validateSchema: true,
+ });
+ addFormatsFunc(ajv);
+
+ const valid = ajv.validateSchema(schema);
+
+ if (!valid && ajv.errors) {
+ for (const err of ajv.errors) {
+ errors.push({
+ path: err.instancePath || '/',
+ message: `${err.keyword}: ${err.message}`,
+ rule: `meta:${err.keyword}`,
+ severity: 'error',
+ });
+ }
+ }
+ }
+
+ // Phase 2: Style rules
+ if (!options.skipStyleRules) {
+ const styleIssues = runLintRules(schema, options.enabledRules, options.disabledRules);
+
+ for (const issue of styleIssues) {
+ if (issue.severity === 'error') {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ }
+
+ return {
+ contract: '',
+ specPath: '',
+ errors,
+ warnings,
+ };
+}
diff --git a/packages/governance/linters/json-schema-rules.ts b/packages/governance/linters/json-schema-rules.ts
new file mode 100644
index 0000000..489b027
--- /dev/null
+++ b/packages/governance/linters/json-schema-rules.ts
@@ -0,0 +1,835 @@
+/**
+ * JSON Schema Linting Rules
+ *
+ * Native TypeScript implementation of linting rules for JSON Schema.
+ * Based on best practices from Sourcemeta, JSON Schema org, and community discussions.
+ *
+ * @see https://github.com/sourcemeta/jsonschema
+ * @see https://github.com/orgs/json-schema-org/discussions/323
+ */
+
+import type { LintIssue, LintSeverity } from '@contractual/types';
+import { type ResolvedSchema, isSchemaObject } from '@contractual/differs.json-schema';
+
+// Re-export ResolvedSchema as SchemaNode for linting API
+export type { ResolvedSchema as SchemaNode } from '@contractual/differs.json-schema';
+
+/**
+ * Lint rule definition
+ */
+export interface LintRule {
+ /** Rule identifier */
+ id: string;
+ /** Human-readable description */
+ description: string;
+ /** Default severity */
+ severity: LintSeverity;
+ /** Check function - returns issues found at this schema node */
+ check: (schema: ResolvedSchema, path: string, root: ResolvedSchema) => LintIssue[];
+}
+
+/**
+ * Keywords that only apply to specific types
+ */
+const TYPE_SPECIFIC_KEYWORDS: Record = {
+ string: ['minLength', 'maxLength', 'pattern', 'format'],
+ number: ['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf'],
+ integer: ['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf'],
+ array: [
+ 'items',
+ 'additionalItems',
+ 'prefixItems',
+ 'contains',
+ 'minItems',
+ 'maxItems',
+ 'uniqueItems',
+ 'minContains',
+ 'maxContains',
+ ],
+ object: [
+ 'properties',
+ 'additionalProperties',
+ 'required',
+ 'minProperties',
+ 'maxProperties',
+ 'patternProperties',
+ 'propertyNames',
+ ],
+ boolean: [],
+ null: [],
+};
+
+/**
+ * Known JSON Schema format values
+ */
+const KNOWN_FORMATS = new Set([
+ // Dates and times (RFC 3339)
+ 'date-time',
+ 'date',
+ 'time',
+ 'duration',
+ // Email (RFC 5321/5322)
+ 'email',
+ 'idn-email',
+ // Hostnames (RFC 1123/5891)
+ 'hostname',
+ 'idn-hostname',
+ // IP addresses (RFC 2673/4291)
+ 'ipv4',
+ 'ipv6',
+ // URIs (RFC 3986/3987)
+ 'uri',
+ 'uri-reference',
+ 'iri',
+ 'iri-reference',
+ 'uri-template',
+ // JSON Pointer (RFC 6901)
+ 'json-pointer',
+ 'relative-json-pointer',
+ // Regex (ECMA 262)
+ 'regex',
+ // UUID (RFC 4122)
+ 'uuid',
+]);
+
+/**
+ * All built-in linting rules
+ */
+export const LINT_RULES: LintRule[] = [
+ // ==========================================
+ // Schema Declaration Rules
+ // ==========================================
+ {
+ id: 'missing-schema',
+ description: 'Root schema should declare $schema',
+ severity: 'warning',
+ check: (schema, path, root) => {
+ // Only check at root
+ if (path !== '/' || schema !== root) return [];
+ if (!schema.$schema) {
+ return [
+ {
+ path: '/',
+ message:
+ 'No $schema declared. Consider adding "$schema": "https://json-schema.org/draft/2020-12/schema"',
+ rule: 'missing-schema',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'schema-not-at-root',
+ description: '$schema should only appear at resource root (with $id) or document root',
+ severity: 'warning',
+ check: (schema, path, root) => {
+ if (path === '/' || schema === root) return [];
+ if (schema.$schema && !schema.$id) {
+ return [
+ {
+ path,
+ message:
+ '$schema without $id in non-root location. $schema should only appear at resource roots.',
+ rule: 'schema-not-at-root',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ // ==========================================
+ // Metadata Rules
+ // ==========================================
+ {
+ id: 'missing-title',
+ description: 'Root schema should have a title',
+ severity: 'warning',
+ check: (schema, path, root) => {
+ if (path !== '/' || schema !== root) return [];
+ if (!schema.title) {
+ return [
+ {
+ path: '/',
+ message: 'Root schema has no title. Consider adding one for documentation.',
+ rule: 'missing-title',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'missing-description',
+ description: 'Root schema should have a description',
+ severity: 'warning',
+ check: (schema, path, root) => {
+ if (path !== '/' || schema !== root) return [];
+ if (!schema.description) {
+ return [
+ {
+ path: '/',
+ message: 'Root schema has no description. Consider adding one for documentation.',
+ rule: 'missing-description',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ // ==========================================
+ // Enum/Const Rules
+ // ==========================================
+ {
+ id: 'enum-to-const',
+ description: 'An enum with a single value should use const instead',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (schema.enum && Array.isArray(schema.enum) && schema.enum.length === 1) {
+ return [
+ {
+ path,
+ message: `An 'enum' with a single value can be expressed as 'const'. Use: "const": ${JSON.stringify(schema.enum[0])}`,
+ rule: 'enum-to-const',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'enum-with-type',
+ description: 'Using type with enum is redundant when enum values are all the same type',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (!schema.enum || !schema.type) return [];
+
+ const enumValues = schema.enum;
+ if (!Array.isArray(enumValues) || enumValues.length === 0) return [];
+
+ // Determine types of all enum values
+ const enumTypes = new Set(
+ enumValues.map((v) => {
+ if (v === null) return 'null';
+ if (Array.isArray(v)) return 'array';
+ return typeof v;
+ })
+ );
+
+ // Map JS types to JSON Schema types
+ const jsToSchema: Record = {
+ string: 'string',
+ number: 'number',
+ boolean: 'boolean',
+ object: 'object',
+ null: 'null',
+ array: 'array',
+ };
+
+ const schemaTypes = new Set([...enumTypes].map((t) => jsToSchema[t] || t));
+ const declaredType = new Set(
+ Array.isArray(schema.type) ? schema.type : [schema.type as string]
+ );
+
+ // Check if type declaration matches enum value types exactly
+ const typesMatch =
+ schemaTypes.size === declaredType.size &&
+ [...schemaTypes].every((t) => declaredType.has(t));
+
+ if (typesMatch) {
+ return [
+ {
+ path,
+ message: "'type' is redundant when 'enum' values already constrain the type",
+ rule: 'enum-with-type',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'const-with-type',
+ description: 'Using type with const is redundant when const value determines the type',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (schema.const === undefined || !schema.type) return [];
+
+ const constValue = schema.const;
+ let constType: string;
+
+ if (constValue === null) {
+ constType = 'null';
+ } else if (Array.isArray(constValue)) {
+ constType = 'array';
+ } else {
+ constType = typeof constValue;
+ }
+
+ // Map JS type to JSON Schema type
+ const jsToSchema: Record = {
+ string: 'string',
+ number: 'number',
+ boolean: 'boolean',
+ object: 'object',
+ null: 'null',
+ array: 'array',
+ };
+ const schemaConstType = jsToSchema[constType] || constType;
+
+ const declaredType = Array.isArray(schema.type) ? schema.type : [schema.type];
+
+ if (declaredType.length === 1 && declaredType[0] === schemaConstType) {
+ return [
+ {
+ path,
+ message: "'type' is redundant when 'const' value already determines the type",
+ rule: 'const-with-type',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ // ==========================================
+ // Conditional Schema Rules
+ // ==========================================
+ {
+ id: 'if-without-then-else',
+ description: 'if without then or else is unnecessary',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (schema.if && !schema.then && !schema.else) {
+ return [
+ {
+ path,
+ message: "'if' without 'then' or 'else' has no effect and can be removed",
+ rule: 'if-without-then-else',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'then-else-without-if',
+ description: 'then or else without if is unnecessary',
+ severity: 'warning',
+ check: (schema, path) => {
+ const issues: LintIssue[] = [];
+ if (schema.then && !schema.if) {
+ issues.push({
+ path,
+ message: "'then' without 'if' has no effect and can be removed",
+ rule: 'then-else-without-if',
+ severity: 'warning',
+ });
+ }
+ if (schema.else && !schema.if) {
+ issues.push({
+ path,
+ message: "'else' without 'if' has no effect and can be removed",
+ rule: 'then-else-without-if',
+ severity: 'warning',
+ });
+ }
+ return issues;
+ },
+ },
+
+ // ==========================================
+ // Array Constraint Rules
+ // ==========================================
+ {
+ id: 'additional-items-redundant',
+ description: 'additionalItems is ignored when items is a schema (not tuple)',
+ severity: 'warning',
+ check: (schema, path) => {
+ // additionalItems only matters when items is an array (tuple validation)
+ // When items is a schema, additionalItems is ignored
+ if (schema.additionalItems !== undefined && schema.items && !Array.isArray(schema.items)) {
+ return [
+ {
+ path,
+ message:
+ "'additionalItems' is ignored when 'items' is a schema (not a tuple). Remove 'additionalItems' or use tuple validation.",
+ rule: 'additional-items-redundant',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'contains-required',
+ description: 'minContains or maxContains without contains is unnecessary',
+ severity: 'warning',
+ check: (schema, path) => {
+ const issues: LintIssue[] = [];
+ if (schema.minContains !== undefined && !schema.contains) {
+ issues.push({
+ path,
+ message: "'minContains' without 'contains' has no effect",
+ rule: 'contains-required',
+ severity: 'warning',
+ });
+ }
+ if (schema.maxContains !== undefined && !schema.contains) {
+ issues.push({
+ path,
+ message: "'maxContains' without 'contains' has no effect",
+ rule: 'contains-required',
+ severity: 'warning',
+ });
+ }
+ return issues;
+ },
+ },
+
+ // ==========================================
+ // Type Compatibility Rules
+ // ==========================================
+ {
+ id: 'type-incompatible-keywords',
+ description: 'Validation keywords that do not apply to the declared type',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (!schema.type || Array.isArray(schema.type)) return [];
+
+ const declaredType = schema.type as string;
+ const applicableKeywords = TYPE_SPECIFIC_KEYWORDS[declaredType] || [];
+ const issues: LintIssue[] = [];
+
+ // Check for keywords that apply to other types
+ for (const [type, keywords] of Object.entries(TYPE_SPECIFIC_KEYWORDS)) {
+ if (type === declaredType) continue;
+
+ for (const keyword of keywords) {
+ if (schema[keyword] !== undefined && !applicableKeywords.includes(keyword)) {
+ issues.push({
+ path,
+ message: `'${keyword}' applies to type '${type}' but schema declares type '${declaredType}'`,
+ rule: 'type-incompatible-keywords',
+ severity: 'warning',
+ });
+ }
+ }
+ }
+
+ return issues;
+ },
+ },
+
+ // ==========================================
+ // Range Validation Rules
+ // ==========================================
+ {
+ id: 'invalid-numeric-range',
+ description: 'maximum should be greater than or equal to minimum',
+ severity: 'error',
+ check: (schema, path) => {
+ const issues: LintIssue[] = [];
+
+ if (typeof schema.minimum === 'number' && typeof schema.maximum === 'number') {
+ if (schema.maximum < schema.minimum) {
+ issues.push({
+ path,
+ message: `'maximum' (${schema.maximum}) is less than 'minimum' (${schema.minimum})`,
+ rule: 'invalid-numeric-range',
+ severity: 'error',
+ });
+ }
+ }
+
+ // Handle exclusive bounds (draft-06+ where they are numbers)
+ if (
+ typeof schema.exclusiveMinimum === 'number' &&
+ typeof schema.exclusiveMaximum === 'number'
+ ) {
+ if (schema.exclusiveMaximum <= schema.exclusiveMinimum) {
+ issues.push({
+ path,
+ message: `'exclusiveMaximum' (${schema.exclusiveMaximum}) is not greater than 'exclusiveMinimum' (${schema.exclusiveMinimum})`,
+ rule: 'invalid-numeric-range',
+ severity: 'error',
+ });
+ }
+ }
+
+ return issues;
+ },
+ },
+
+ {
+ id: 'invalid-length-range',
+ description: 'maxLength should be greater than or equal to minLength',
+ severity: 'error',
+ check: (schema, path) => {
+ if (typeof schema.minLength === 'number' && typeof schema.maxLength === 'number') {
+ if (schema.maxLength < schema.minLength) {
+ return [
+ {
+ path,
+ message: `'maxLength' (${schema.maxLength}) is less than 'minLength' (${schema.minLength})`,
+ rule: 'invalid-length-range',
+ severity: 'error',
+ },
+ ];
+ }
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'invalid-items-range',
+ description: 'maxItems should be greater than or equal to minItems',
+ severity: 'error',
+ check: (schema, path) => {
+ if (typeof schema.minItems === 'number' && typeof schema.maxItems === 'number') {
+ if (schema.maxItems < schema.minItems) {
+ return [
+ {
+ path,
+ message: `'maxItems' (${schema.maxItems}) is less than 'minItems' (${schema.minItems})`,
+ rule: 'invalid-items-range',
+ severity: 'error',
+ },
+ ];
+ }
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'invalid-properties-range',
+ description: 'maxProperties should be greater than or equal to minProperties',
+ severity: 'error',
+ check: (schema, path) => {
+ if (typeof schema.minProperties === 'number' && typeof schema.maxProperties === 'number') {
+ if (schema.maxProperties < schema.minProperties) {
+ return [
+ {
+ path,
+ message: `'maxProperties' (${schema.maxProperties}) is less than 'minProperties' (${schema.minProperties})`,
+ rule: 'invalid-properties-range',
+ severity: 'error',
+ },
+ ];
+ }
+ }
+ return [];
+ },
+ },
+
+ // ==========================================
+ // Format Rules
+ // ==========================================
+ {
+ id: 'unknown-format',
+ description: 'Unknown format value may not be validated',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (typeof schema.format === 'string' && !KNOWN_FORMATS.has(schema.format)) {
+ return [
+ {
+ path,
+ message: `Unknown format '${schema.format}'. Custom formats may not be validated by all implementations.`,
+ rule: 'unknown-format',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ // ==========================================
+ // Empty Schema Rules
+ // ==========================================
+ {
+ id: 'empty-enum',
+ description: 'Empty enum matches nothing and is likely an error',
+ severity: 'error',
+ check: (schema, path) => {
+ if (schema.enum && Array.isArray(schema.enum) && schema.enum.length === 0) {
+ return [
+ {
+ path,
+ message: "Empty 'enum' array will never validate any value",
+ rule: 'empty-enum',
+ severity: 'error',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'empty-required',
+ description: 'Empty required array is unnecessary',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (schema.required && Array.isArray(schema.required) && schema.required.length === 0) {
+ return [
+ {
+ path,
+ message: "Empty 'required' array can be removed",
+ rule: 'empty-required',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+
+ {
+ id: 'empty-allof-anyof-oneof',
+ description: 'Empty allOf/anyOf/oneOf is likely an error',
+ severity: 'error',
+ check: (schema, path) => {
+ const issues: LintIssue[] = [];
+ for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {
+ const value = schema[keyword];
+ if (value && Array.isArray(value) && value.length === 0) {
+ issues.push({
+ path,
+ message: `Empty '${keyword}' array ${keyword === 'anyOf' || keyword === 'oneOf' ? 'will never validate' : 'is redundant'}`,
+ rule: 'empty-allof-anyof-oneof',
+ severity: keyword === 'allOf' ? 'warning' : 'error',
+ });
+ }
+ }
+ return issues;
+ },
+ },
+
+ // ==========================================
+ // Required Properties Rules
+ // ==========================================
+ {
+ id: 'required-undefined-property',
+ description: 'Required property is not defined in properties',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (!schema.required || !schema.properties) return [];
+
+ const issues: LintIssue[] = [];
+ const definedProps = new Set(Object.keys(schema.properties));
+
+ for (const requiredProp of schema.required) {
+ if (!definedProps.has(requiredProp)) {
+ issues.push({
+ path,
+ message: `Required property '${requiredProp}' is not defined in 'properties'`,
+ rule: 'required-undefined-property',
+ severity: 'warning',
+ });
+ }
+ }
+ return issues;
+ },
+ },
+
+ {
+ id: 'duplicate-required',
+ description: 'Duplicate entries in required array',
+ severity: 'warning',
+ check: (schema, path) => {
+ if (!schema.required || !Array.isArray(schema.required)) return [];
+
+ const seen = new Set();
+ const duplicates = new Set();
+
+ for (const prop of schema.required) {
+ if (seen.has(prop)) {
+ duplicates.add(prop);
+ }
+ seen.add(prop);
+ }
+
+ if (duplicates.size > 0) {
+ return [
+ {
+ path,
+ message: `Duplicate entries in 'required': ${[...duplicates].join(', ')}`,
+ rule: 'duplicate-required',
+ severity: 'warning',
+ },
+ ];
+ }
+ return [];
+ },
+ },
+];
+
+/**
+ * Run all lint rules against a schema, recursively walking all subschemas
+ */
+export function runLintRules(
+ schema: ResolvedSchema,
+ enabledRules?: Set,
+ disabledRules?: Set
+): LintIssue[] {
+ const issues: LintIssue[] = [];
+ const activeRules = LINT_RULES.filter((rule) => {
+ if (disabledRules?.has(rule.id)) return false;
+ if (enabledRules && !enabledRules.has(rule.id)) return false;
+ return true;
+ });
+
+ walkSchema(schema, '/', schema, (node, path, root) => {
+ for (const rule of activeRules) {
+ const ruleIssues = rule.check(node, path, root);
+ issues.push(...ruleIssues);
+ }
+ });
+
+ return issues;
+}
+
+/**
+ * Walk all subschemas in a JSON Schema document
+ */
+function walkSchema(
+ schema: ResolvedSchema,
+ path: string,
+ root: ResolvedSchema,
+ visitor: (node: ResolvedSchema, path: string, root: ResolvedSchema) => void
+): void {
+ if (!isSchemaObject(schema)) return;
+
+ visitor(schema, path, root);
+
+ // Properties
+ if (schema.properties) {
+ for (const [key, value] of Object.entries(schema.properties)) {
+ if (isSchemaObject(value)) {
+ walkSchema(value, `${path}/properties/${key}`, root, visitor);
+ }
+ }
+ }
+
+ // Additional properties
+ if (isSchemaObject(schema.additionalProperties)) {
+ walkSchema(schema.additionalProperties, `${path}/additionalProperties`, root, visitor);
+ }
+
+ // Pattern properties
+ if (schema.patternProperties) {
+ for (const [pattern, value] of Object.entries(schema.patternProperties)) {
+ if (isSchemaObject(value)) {
+ walkSchema(
+ value,
+ `${path}/patternProperties/${encodeURIComponent(pattern)}`,
+ root,
+ visitor
+ );
+ }
+ }
+ }
+
+ // Property names
+ if (isSchemaObject(schema.propertyNames)) {
+ walkSchema(schema.propertyNames, `${path}/propertyNames`, root, visitor);
+ }
+
+ // Items (array or single schema)
+ if (schema.items) {
+ if (Array.isArray(schema.items)) {
+ schema.items.forEach((item, i) => {
+ if (isSchemaObject(item)) {
+ walkSchema(item, `${path}/items/${i}`, root, visitor);
+ }
+ });
+ } else if (isSchemaObject(schema.items)) {
+ walkSchema(schema.items, `${path}/items`, root, visitor);
+ }
+ }
+
+ // Prefix items (2020-12)
+ if (schema.prefixItems && Array.isArray(schema.prefixItems)) {
+ schema.prefixItems.forEach((item, i) => {
+ if (isSchemaObject(item)) {
+ walkSchema(item, `${path}/prefixItems/${i}`, root, visitor);
+ }
+ });
+ }
+
+ // Contains
+ if (isSchemaObject(schema.contains)) {
+ walkSchema(schema.contains, `${path}/contains`, root, visitor);
+ }
+
+ // Conditional
+ if (isSchemaObject(schema.if)) {
+ walkSchema(schema.if, `${path}/if`, root, visitor);
+ }
+ if (isSchemaObject(schema.then)) {
+ walkSchema(schema.then, `${path}/then`, root, visitor);
+ }
+ if (isSchemaObject(schema.else)) {
+ walkSchema(schema.else, `${path}/else`, root, visitor);
+ }
+
+ // Composition
+ for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {
+ const arr = schema[keyword];
+ if (arr && Array.isArray(arr)) {
+ arr.forEach((item, i) => {
+ if (isSchemaObject(item)) {
+ walkSchema(item, `${path}/${keyword}/${i}`, root, visitor);
+ }
+ });
+ }
+ }
+
+ // Not
+ if (isSchemaObject(schema.not)) {
+ walkSchema(schema.not, `${path}/not`, root, visitor);
+ }
+
+ // Definitions ($defs)
+ if (schema.$defs) {
+ for (const [key, value] of Object.entries(schema.$defs)) {
+ if (isSchemaObject(value)) {
+ walkSchema(value, `${path}/$defs/${key}`, root, visitor);
+ }
+ }
+ }
+}
+
+/**
+ * Get all available rule IDs
+ */
+export function getAvailableRules(): string[] {
+ return LINT_RULES.map((r) => r.id);
+}
+
+/**
+ * Get rule description by ID
+ */
+export function getRuleDescription(ruleId: string): string | undefined {
+ return LINT_RULES.find((r) => r.id === ruleId)?.description;
+}
diff --git a/packages/governance/linters/openapi-redocly.ts b/packages/governance/linters/openapi-redocly.ts
new file mode 100644
index 0000000..fc6862e
--- /dev/null
+++ b/packages/governance/linters/openapi-redocly.ts
@@ -0,0 +1,78 @@
+/**
+ * OpenAPI Linter using @redocly/openapi-core
+ *
+ * Wraps Redocly's OpenAPI linting library to validate OpenAPI specs.
+ * Users can place a .redocly.yaml in their repo for custom rules.
+ */
+
+import type { LintResult, LintIssue } from '@contractual/types';
+
+/**
+ * Lint an OpenAPI specification using Redocly
+ *
+ * @param specPath - Path to the OpenAPI spec file
+ * @returns Lint result with errors and warnings
+ */
+export async function lintOpenAPI(specPath: string): Promise {
+ // Dynamic import to handle the library being optional
+ let lint: typeof import('@redocly/openapi-core').lint;
+ let loadConfig: typeof import('@redocly/openapi-core').loadConfig;
+
+ try {
+ const redocly = await import('@redocly/openapi-core');
+ lint = redocly.lint;
+ loadConfig = redocly.loadConfig;
+ } catch {
+ throw new Error(
+ 'OpenAPI linting requires @redocly/openapi-core. ' +
+ 'Install it with: npm install @redocly/openapi-core'
+ );
+ }
+
+ const errors: LintIssue[] = [];
+ const warnings: LintIssue[] = [];
+
+ try {
+ // Load config from .redocly.yaml if present, or use defaults
+ const config = await loadConfig();
+
+ // Run the linter
+ const results = await lint({
+ ref: specPath,
+ config,
+ });
+
+ // Process problems
+ for (const problem of results) {
+ const issue: LintIssue = {
+ path: problem.location?.[0]?.pointer ?? '',
+ message: problem.message,
+ rule: problem.ruleId,
+ severity: problem.severity === 'error' ? 'error' : 'warning',
+ };
+
+ if (issue.severity === 'error') {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ } catch (error: unknown) {
+ // Handle parse errors or file not found
+ const message = error instanceof Error ? error.message : 'Unknown error during linting';
+
+ errors.push({
+ path: '/',
+ message,
+ rule: 'parse-error',
+ severity: 'error',
+ });
+ }
+
+ return {
+ contract: '', // Filled by caller
+ specPath,
+ errors,
+ warnings,
+ };
+}
diff --git a/packages/governance/package.json b/packages/governance/package.json
new file mode 100644
index 0000000..454023e
--- /dev/null
+++ b/packages/governance/package.json
@@ -0,0 +1,59 @@
+{
+ "name": "@contractual/governance",
+ "private": false,
+ "version": "0.1.0-dev.5",
+ "license": "MIT",
+ "type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ },
+ "./linters": {
+ "types": "./dist/linters/index.d.ts",
+ "import": "./dist/linters/index.js"
+ },
+ "./differs": {
+ "types": "./dist/differs/index.d.ts",
+ "import": "./dist/differs/index.js"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/governance"
+ },
+ "homepage": "https://contractual.dev",
+ "bugs": {
+ "url": "https://github.com/contractual-dev/contractual/issues"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "pnpm rimraf dist",
+ "build": "tsc -p tsconfig.build.json",
+ "build:watch": "tsc -p tsconfig.build.json --watch",
+ "lint": "eslint \"linters/**/*.ts\" \"differs/**/*.ts\" \"*.ts\""
+ },
+ "files": [
+ "dist",
+ "README.md"
+ ],
+ "dependencies": {
+ "@contractual/differs.json-schema": "workspace:*",
+ "@contractual/differs.openapi": "workspace:*",
+ "@contractual/types": "workspace:*",
+ "ajv": "^8.17.1",
+ "ajv-formats": "^3.0.1"
+ },
+ "devDependencies": {
+ "@redocly/openapi-core": "^1.0.0"
+ },
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/governance/registry.ts b/packages/governance/registry.ts
new file mode 100644
index 0000000..2ed1f78
--- /dev/null
+++ b/packages/governance/registry.ts
@@ -0,0 +1,198 @@
+/**
+ * Governance Registry
+ *
+ * Central registry for linters and differs. CLI Core uses this to resolve
+ * the correct engine for each contract type.
+ */
+
+import type { LintFn, DiffFn, ContractType } from '@contractual/types';
+
+const linters = new Map();
+const differs = new Map();
+
+/**
+ * Register a linter for a contract type
+ */
+export function registerLinter(type: ContractType, linter: LintFn): void {
+ linters.set(type, linter);
+}
+
+/**
+ * Register a differ for a contract type
+ */
+export function registerDiffer(type: ContractType, differ: DiffFn): void {
+ differs.set(type, differ);
+}
+
+/**
+ * Get the linter for a contract type
+ *
+ * @param type - Contract type (openapi, json-schema, etc.)
+ * @param override - Optional override: built-in name or custom command
+ * @returns Linter function or null if not found
+ */
+export function getLinter(type: ContractType, override?: string | false): LintFn | null {
+ // If override is explicitly false, disable linting
+ if (override === false) {
+ return null;
+ }
+
+ // If override is a custom command (contains {spec}), create custom executor
+ if (override && override.includes('{spec}')) {
+ return createCustomLinter(override);
+ }
+
+ // If override is a known built-in name, resolve it
+ if (override) {
+ const builtIn = resolveBuiltInLinter(override);
+ if (builtIn) return builtIn;
+ }
+
+ // Return default for type
+ return linters.get(type) ?? null;
+}
+
+/**
+ * Get the differ for a contract type
+ *
+ * @param type - Contract type (openapi, json-schema, etc.)
+ * @param override - Optional override: built-in name or custom command
+ * @returns Differ function or null if not found
+ */
+export function getDiffer(type: ContractType, override?: string | false): DiffFn | null {
+ // If override is explicitly false, disable diffing
+ if (override === false) {
+ return null;
+ }
+
+ // If override is a custom command (contains {old} or {new}), create custom executor
+ if (override && (override.includes('{old}') || override.includes('{new}'))) {
+ return createCustomDiffer(override);
+ }
+
+ // If override is a known built-in name, resolve it
+ if (override) {
+ const builtIn = resolveBuiltInDiffer(override);
+ if (builtIn) return builtIn;
+ }
+
+ // Return default for type
+ return differs.get(type) ?? null;
+}
+
+/**
+ * Valid contract type values for type checking
+ */
+const VALID_CONTRACT_TYPES: readonly ContractType[] = [
+ 'openapi',
+ 'json-schema',
+ 'asyncapi',
+ 'odcs',
+] as const;
+
+/**
+ * Type guard for ContractType
+ */
+function isContractType(value: string): value is ContractType {
+ return VALID_CONTRACT_TYPES.includes(value as ContractType);
+}
+
+/**
+ * Resolve a built-in linter by name
+ */
+function resolveBuiltInLinter(name: string): LintFn | null {
+ // Check if name is a valid contract type
+ if (isContractType(name)) {
+ const linter = linters.get(name);
+ if (linter) return linter;
+ }
+
+ // Special named overrides
+ switch (name.toLowerCase()) {
+ case 'redocly':
+ case 'openapi-redocly':
+ return linters.get('openapi') ?? null;
+ case 'spectral':
+ // Spectral is an alternative OpenAPI linter - could add support later
+ return linters.get('openapi') ?? null;
+ case 'ajv':
+ case 'json-schema-ajv':
+ return linters.get('json-schema') ?? null;
+ default:
+ return null;
+ }
+}
+
+/**
+ * Resolve a built-in differ by name
+ */
+function resolveBuiltInDiffer(name: string): DiffFn | null {
+ // Check if name is a valid contract type
+ if (isContractType(name)) {
+ const differ = differs.get(name);
+ if (differ) return differ;
+ }
+
+ // Special named overrides
+ switch (name.toLowerCase()) {
+ case 'oasdiff':
+ case 'openapi-oasdiff':
+ return differs.get('openapi') ?? null;
+ case 'json-schema-differ':
+ return differs.get('json-schema') ?? null;
+ default:
+ return null;
+ }
+}
+
+/**
+ * Create a custom linter from a command template
+ */
+function createCustomLinter(commandTemplate: string): LintFn {
+ return async (specPath: string) => {
+ const { executeCustomCommand, parseCustomLintOutput } = await import('./runner.js');
+ const command = commandTemplate.replace('{spec}', specPath);
+ const output = await executeCustomCommand(command);
+ return parseCustomLintOutput(output);
+ };
+}
+
+/**
+ * Create a custom differ from a command template
+ */
+function createCustomDiffer(commandTemplate: string): DiffFn {
+ return async (oldSpecPath: string, newSpecPath: string) => {
+ const { executeCustomCommand, parseCustomDiffOutput } = await import('./runner.js');
+ const command = commandTemplate.replace('{old}', oldSpecPath).replace('{new}', newSpecPath);
+ const output = await executeCustomCommand(command);
+ return parseCustomDiffOutput(output);
+ };
+}
+
+/**
+ * Check if a linter is registered for a contract type
+ */
+export function hasLinter(type: ContractType): boolean {
+ return linters.has(type);
+}
+
+/**
+ * Check if a differ is registered for a contract type
+ */
+export function hasDiffer(type: ContractType): boolean {
+ return differs.has(type);
+}
+
+/**
+ * Get all registered contract types for linting
+ */
+export function getRegisteredLinterTypes(): ContractType[] {
+ return Array.from(linters.keys());
+}
+
+/**
+ * Get all registered contract types for diffing
+ */
+export function getRegisteredDifferTypes(): ContractType[] {
+ return Array.from(differs.keys());
+}
diff --git a/packages/governance/runner.ts b/packages/governance/runner.ts
new file mode 100644
index 0000000..0812b07
--- /dev/null
+++ b/packages/governance/runner.ts
@@ -0,0 +1,366 @@
+/**
+ * Custom Command Runner
+ *
+ * Executes user-defined governance commands and parses their output.
+ */
+
+import { execSync } from 'node:child_process';
+import type { LintResult, DiffResult, LintIssue, Change } from '@contractual/types';
+
+/**
+ * Shape of exec error with additional properties
+ */
+interface ExecError extends Error {
+ stdout?: string;
+ stderr?: string;
+ status?: number;
+ signal?: string;
+}
+
+/**
+ * Type guard for ExecError
+ */
+function isExecError(error: unknown): error is ExecError {
+ return error instanceof Error;
+}
+
+/**
+ * Execute a custom command and return its output
+ *
+ * Note: This function is async for API consistency with other governance functions,
+ * even though the underlying execSync is synchronous. This allows for future
+ * migration to async child_process.spawn if needed.
+ *
+ * @param command - Command to execute
+ * @param timeout - Timeout in milliseconds (default: 60000)
+ * @returns Command stdout
+ * @throws Error if command fails
+ */
+export async function executeCustomCommand(command: string, timeout = 60000): Promise {
+ try {
+ const stdout = execSync(command, {
+ encoding: 'utf-8',
+ timeout,
+ stdio: ['pipe', 'pipe', 'pipe'],
+ });
+ return stdout;
+ } catch (error: unknown) {
+ // Type-safe error handling
+ if (isExecError(error)) {
+ // Some tools exit with non-zero when issues found - return stdout if available
+ if (error.stdout) {
+ return error.stdout;
+ }
+
+ throw new Error(
+ `Custom command failed: ${command}\n` +
+ `Exit code: ${error.status ?? 'unknown'}\n` +
+ `Stderr: ${error.stderr ?? error.message}`
+ );
+ }
+
+ throw new Error(`Custom command failed: ${command}\n${String(error)}`);
+ }
+}
+
+/**
+ * Parse custom lint command output into LintResult
+ *
+ * Attempts to parse as JSON first, then falls back to line-based parsing.
+ */
+export function parseCustomLintOutput(output: string): LintResult {
+ const trimmed = output.trim();
+
+ // Try JSON parsing first
+ if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
+ try {
+ const parsed = JSON.parse(trimmed);
+ return normalizeJsonLintOutput(parsed);
+ } catch {
+ // Fall through to line-based parsing
+ }
+ }
+
+ // Line-based parsing for text output
+ return parseLineLintOutput(trimmed);
+}
+
+/**
+ * Parse custom diff command output into DiffResult
+ *
+ * Attempts to parse as JSON first, then falls back to line-based parsing.
+ */
+export function parseCustomDiffOutput(output: string): DiffResult {
+ const trimmed = output.trim();
+
+ // Try JSON parsing first
+ if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
+ try {
+ const parsed = JSON.parse(trimmed);
+ return normalizeJsonDiffOutput(parsed);
+ } catch {
+ // Fall through to line-based parsing
+ }
+ }
+
+ // Line-based parsing for text output
+ return parseLineDiffOutput(trimmed);
+}
+
+/**
+ * Normalize JSON lint output from various tools
+ */
+function normalizeJsonLintOutput(parsed: unknown): LintResult {
+ const errors: LintIssue[] = [];
+ const warnings: LintIssue[] = [];
+
+ if (Array.isArray(parsed)) {
+ for (const item of parsed) {
+ const issue = normalizeIssue(item);
+ if (issue.severity === 'error') {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ } else if (typeof parsed === 'object' && parsed !== null) {
+ // Handle object with errors/warnings arrays
+ const obj = parsed as Record;
+ if (Array.isArray(obj.errors)) {
+ errors.push(...obj.errors.map((e) => normalizeIssue(e, 'error')));
+ }
+ if (Array.isArray(obj.warnings)) {
+ warnings.push(...obj.warnings.map((w) => normalizeIssue(w, 'warning')));
+ }
+ if (Array.isArray(obj.problems)) {
+ for (const p of obj.problems) {
+ const issue = normalizeIssue(p);
+ if (issue.severity === 'error') {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ }
+ }
+
+ return { contract: '', specPath: '', errors, warnings };
+}
+
+/**
+ * Normalize a single issue from various formats
+ */
+function normalizeIssue(item: unknown, defaultSeverity: 'error' | 'warning' = 'error'): LintIssue {
+ if (typeof item === 'string') {
+ return {
+ path: '',
+ message: item,
+ severity: defaultSeverity,
+ };
+ }
+
+ if (typeof item !== 'object' || item === null) {
+ return {
+ path: '',
+ message: String(item),
+ severity: defaultSeverity,
+ };
+ }
+
+ const obj = item as Record;
+
+ // Common field mappings
+ const path = String(obj.path ?? obj.location ?? obj.pointer ?? obj.instancePath ?? '');
+ const message = String(obj.message ?? obj.text ?? obj.description ?? obj.msg ?? '');
+ const rule = obj.rule ?? obj.ruleId ?? obj.code ?? obj.id;
+ const severity = normalizeSeverity(obj.severity ?? obj.level ?? defaultSeverity);
+
+ return {
+ path,
+ message,
+ rule: rule ? String(rule) : undefined,
+ severity,
+ };
+}
+
+/**
+ * Normalize severity from various formats
+ */
+function normalizeSeverity(value: unknown): 'error' | 'warning' {
+ if (typeof value === 'number') {
+ // Common: 0=error, 1=warning, 2=info (Spectral)
+ // Or: 1=error, 2=warning, 3=info (some tools)
+ return value <= 1 ? 'error' : 'warning';
+ }
+ if (typeof value === 'string') {
+ const lower = value.toLowerCase();
+ if (lower === 'error' || lower === 'err' || lower === 'fatal') {
+ return 'error';
+ }
+ }
+ return 'warning';
+}
+
+/**
+ * Parse line-based lint output
+ */
+function parseLineLintOutput(output: string): LintResult {
+ const errors: LintIssue[] = [];
+ const warnings: LintIssue[] = [];
+
+ const lines = output.split('\n').filter((line) => line.trim());
+
+ for (const line of lines) {
+ // Common patterns:
+ // "error: message" or "warning: message"
+ // "path:line:col: error message"
+ // "[ERROR] message"
+
+ const lowerLine = line.toLowerCase();
+ const isError =
+ lowerLine.includes('error') || lowerLine.includes('[err]') || lowerLine.startsWith('e ');
+ const isWarning =
+ lowerLine.includes('warning') || lowerLine.includes('[warn]') || lowerLine.startsWith('w ');
+
+ if (isError || isWarning || line.includes(':')) {
+ const issue: LintIssue = {
+ path: '',
+ message: line.trim(),
+ severity: isError ? 'error' : 'warning',
+ };
+
+ if (isError) {
+ errors.push(issue);
+ } else {
+ warnings.push(issue);
+ }
+ }
+ }
+
+ return { contract: '', specPath: '', errors, warnings };
+}
+
+/**
+ * Normalize JSON diff output from various tools
+ */
+function normalizeJsonDiffOutput(parsed: unknown): DiffResult {
+ const changes: Change[] = [];
+
+ if (Array.isArray(parsed)) {
+ for (const item of parsed) {
+ changes.push(normalizeChange(item));
+ }
+ } else if (typeof parsed === 'object' && parsed !== null) {
+ const obj = parsed as Record;
+ // Handle object with changes/items array
+ const items = obj.changes ?? obj.items ?? obj.differences ?? [];
+ if (Array.isArray(items)) {
+ for (const item of items) {
+ changes.push(normalizeChange(item));
+ }
+ }
+ }
+
+ const summary = {
+ breaking: changes.filter((c) => c.severity === 'breaking').length,
+ nonBreaking: changes.filter((c) => c.severity === 'non-breaking').length,
+ patch: changes.filter((c) => c.severity === 'patch').length,
+ unknown: changes.filter((c) => c.severity === 'unknown').length,
+ };
+
+ const suggestedBump =
+ summary.breaking > 0
+ ? 'major'
+ : summary.nonBreaking > 0
+ ? 'minor'
+ : summary.patch > 0
+ ? 'patch'
+ : 'none';
+
+ return { contract: '', changes, summary, suggestedBump };
+}
+
+/**
+ * Normalize a single change from various formats
+ */
+function normalizeChange(item: unknown): Change {
+ if (typeof item !== 'object' || item === null) {
+ return {
+ path: '',
+ severity: 'unknown',
+ category: 'unknown-change',
+ message: String(item),
+ };
+ }
+
+ const obj = item as Record;
+
+ const path = String(obj.path ?? obj.location ?? obj.pointer ?? '');
+ const message = String(obj.message ?? obj.text ?? obj.description ?? '');
+ const category = String(obj.category ?? obj.code ?? obj.id ?? 'unknown-change');
+
+ // Determine severity
+ let severity: Change['severity'] = 'unknown';
+ if (obj.severity) {
+ const sev = String(obj.severity).toLowerCase();
+ if (sev === 'breaking' || sev === 'major') {
+ severity = 'breaking';
+ } else if (sev === 'non-breaking' || sev === 'minor') {
+ severity = 'non-breaking';
+ } else if (sev === 'patch') {
+ severity = 'patch';
+ }
+ } else if (obj.level !== undefined) {
+ // oasdiff style: level 3 = breaking
+ const level = Number(obj.level);
+ if (level === 3) severity = 'breaking';
+ else if (level === 2) severity = 'non-breaking';
+ else if (level === 1) severity = 'patch';
+ } else if (obj.breaking === true) {
+ severity = 'breaking';
+ }
+
+ return {
+ path,
+ severity,
+ category,
+ message,
+ oldValue: obj.oldValue ?? obj.old ?? obj.from,
+ newValue: obj.newValue ?? obj.new ?? obj.to,
+ };
+}
+
+/**
+ * Parse line-based diff output
+ */
+function parseLineDiffOutput(output: string): DiffResult {
+ const changes: Change[] = [];
+
+ const lines = output.split('\n').filter((line) => line.trim());
+
+ for (const line of lines) {
+ const lowerLine = line.toLowerCase();
+ const isBreaking =
+ lowerLine.includes('breaking') ||
+ lowerLine.includes('removed') ||
+ lowerLine.includes('major');
+
+ changes.push({
+ path: '',
+ severity: isBreaking ? 'breaking' : 'unknown',
+ category: 'unknown-change',
+ message: line.trim(),
+ });
+ }
+
+ const summary = {
+ breaking: changes.filter((c) => c.severity === 'breaking').length,
+ nonBreaking: 0,
+ patch: 0,
+ unknown: changes.filter((c) => c.severity === 'unknown').length,
+ };
+
+ const suggestedBump = summary.breaking > 0 ? 'major' : 'none';
+
+ return { contract: '', changes, summary, suggestedBump };
+}
diff --git a/packages/governance/tsconfig.build.json b/packages/governance/tsconfig.build.json
new file mode 100644
index 0000000..8ed7148
--- /dev/null
+++ b/packages/governance/tsconfig.build.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "composite": true
+ },
+ "references": [
+ { "path": "../types/tsconfig.build.json" }
+ ],
+ "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
+}
diff --git a/packages/governance/tsconfig.json b/packages/governance/tsconfig.json
new file mode 100644
index 0000000..3bdc553
--- /dev/null
+++ b/packages/governance/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "./dist",
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true
+ },
+ "include": ["**/*.ts"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/packages/types/config.ts b/packages/types/config.ts
new file mode 100644
index 0000000..7edb48d
--- /dev/null
+++ b/packages/types/config.ts
@@ -0,0 +1,164 @@
+/**
+ * Supported contract types in Contractual.
+ *
+ * @remarks
+ * - `openapi` - OpenAPI 3.x specifications
+ * - `json-schema` - JSON Schema (Draft-07, 2019-09, 2020-12)
+ * - `asyncapi` - AsyncAPI 2.x/3.x specifications
+ * - `odcs` - Open Data Contract Standard v3.x
+ */
+export type ContractType = 'openapi' | 'json-schema' | 'asyncapi' | 'odcs';
+
+/**
+ * All valid contract type values as a readonly array.
+ * Useful for runtime validation and iteration.
+ */
+export const CONTRACT_TYPES = [
+ 'openapi',
+ 'json-schema',
+ 'asyncapi',
+ 'odcs',
+] as const satisfies readonly ContractType[];
+
+/**
+ * Definition of a single contract in the configuration file.
+ *
+ * @example
+ * ```yaml
+ * contracts:
+ * - name: orders-api
+ * type: openapi
+ * path: ./specs/orders.openapi.yaml
+ * ```
+ */
+export interface ContractDefinition {
+ /** Unique identifier for the contract, used in changeset files and version history */
+ name: string;
+ /** Type of schema format */
+ type: ContractType;
+ /** Path to spec file, relative to config (can be glob pattern) */
+ path: string;
+ /** Override linter: tool name, custom command with {spec} placeholder, or false to disable */
+ lint?: string | false;
+ /** Override differ: tool name, custom command with {old} {new} placeholders, or false to disable */
+ breaking?: string | false;
+ /** Sync version field inside the spec file on version bump (default: true). Set to false to skip. */
+ syncVersion?: boolean;
+ /** Output generation commands (Phase 2) */
+ generate?: string[];
+}
+
+/**
+ * Changeset behavior configuration.
+ */
+export interface ChangesetConfig {
+ /** Auto-detect change classifications from structural diff (default: true) */
+ autoDetect?: boolean;
+ /** Require changeset for spec changes in PRs (default: true) */
+ requireOnPR?: boolean;
+}
+
+/**
+ * AI provider types supported by Contractual.
+ */
+export type AIProvider = 'anthropic';
+
+/**
+ * AI feature toggles.
+ */
+export interface AIFeatures {
+ /** Enable PR change explanations */
+ explain?: boolean;
+ /** Enable AI-enriched changelog entries */
+ changelog?: boolean;
+ /** Enable spec metadata enhancement (auto-fill descriptions, examples) */
+ enhance?: boolean;
+}
+
+/**
+ * AI/LLM integration configuration.
+ *
+ * @remarks
+ * All AI features gracefully degrade when no API key is provided.
+ */
+export interface AIConfig {
+ /** AI provider (only 'anthropic' supported currently) */
+ provider?: AIProvider;
+ /** Model identifier to use */
+ model?: string;
+ /** Feature toggles */
+ features?: AIFeatures;
+}
+
+/**
+ * Versioning mode for contracts.
+ *
+ * - `independent` - Each contract has its own version (like Lerna independent mode)
+ * - `fixed` - All contracts share the same version
+ */
+export type VersioningMode = 'independent' | 'fixed';
+
+/**
+ * Versioning configuration.
+ */
+export interface VersioningConfig {
+ /** Versioning mode (default: 'independent') */
+ mode: VersioningMode;
+}
+
+/**
+ * Root configuration for contractual.yaml.
+ *
+ * @example
+ * ```yaml
+ * contracts:
+ * - name: orders-api
+ * type: openapi
+ * path: ./specs/orders.openapi.yaml
+ *
+ * ai:
+ * features:
+ * explain: true
+ * changelog: true
+ * ```
+ */
+export interface ContractualConfig {
+ /** List of contract definitions */
+ contracts: ContractDefinition[];
+ /** Versioning configuration */
+ versioning?: VersioningConfig;
+ /** Changeset behavior configuration */
+ changeset?: ChangesetConfig;
+ /** AI/LLM integration configuration */
+ ai?: AIConfig;
+}
+
+/**
+ * Resolved contract with absolute paths and validated data.
+ */
+export interface ResolvedContract extends ContractDefinition {
+ /** Absolute path to the spec file */
+ absolutePath: string;
+}
+
+/**
+ * Fully resolved configuration with absolute paths.
+ */
+export interface ResolvedConfig extends Omit {
+ /** Resolved contracts with absolute paths */
+ contracts: ResolvedContract[];
+ /** Directory containing contractual.yaml */
+ configDir: string;
+ /** Absolute path to contractual.yaml */
+ configPath: string;
+}
+
+/**
+ * Type guard to check if a string is a valid ContractType.
+ *
+ * @param value - The value to check
+ * @returns True if the value is a valid ContractType
+ */
+export function isContractType(value: unknown): value is ContractType {
+ return typeof value === 'string' && CONTRACT_TYPES.includes(value as ContractType);
+}
diff --git a/packages/types/governance.ts b/packages/types/governance.ts
new file mode 100644
index 0000000..a6c4db9
--- /dev/null
+++ b/packages/types/governance.ts
@@ -0,0 +1,374 @@
+/**
+ * Severity classification for detected changes between spec versions.
+ *
+ * @remarks
+ * - `breaking` - Changes that will break existing consumers (major bump)
+ * - `non-breaking` - Additive changes that are backwards compatible (minor bump)
+ * - `patch` - Metadata-only changes (patch bump)
+ * - `unknown` - Complex changes requiring manual review
+ */
+export type ChangeSeverity = 'breaking' | 'non-breaking' | 'patch' | 'unknown';
+
+/**
+ * A single change detected between two spec versions.
+ *
+ * @example
+ * ```typescript
+ * const change: Change = {
+ * path: '/properties/amount/type',
+ * severity: 'breaking',
+ * category: 'type-changed',
+ * message: "Changed type of field 'amount': string -> number",
+ * oldValue: 'string',
+ * newValue: 'number'
+ * };
+ * ```
+ */
+export interface Change {
+ /** JSON Pointer path to the changed element (e.g., "/properties/amount/type") */
+ path: string;
+ /** Severity classification determining version bump */
+ severity: ChangeSeverity;
+ /** Category key for grouping similar changes (e.g., "field-removed", "type-changed") */
+ category: string;
+ /** Human-readable description of the change */
+ message: string;
+ /** Value in the old spec (undefined if added) */
+ oldValue?: unknown;
+ /** Value in the new spec (undefined if removed) */
+ newValue?: unknown;
+}
+
+/**
+ * Summary counts of changes by severity.
+ */
+export interface DiffSummary {
+ /** Number of breaking changes detected */
+ breaking: number;
+ /** Number of non-breaking (additive) changes detected */
+ nonBreaking: number;
+ /** Number of patch-level (metadata) changes detected */
+ patch: number;
+ /** Number of unclassifiable changes requiring manual review */
+ unknown: number;
+}
+
+/**
+ * Suggested semver bump based on detected changes.
+ *
+ * @remarks
+ * - `major` - Breaking changes detected
+ * - `minor` - Non-breaking structural changes
+ * - `patch` - Metadata-only changes
+ * - `none` - No changes detected
+ */
+export type SuggestedBump = 'major' | 'minor' | 'patch' | 'none';
+
+/**
+ * Result of comparing two spec versions.
+ */
+export interface DiffResult {
+ /** Contract name from config */
+ contract: string;
+ /** List of all detected changes */
+ changes: Change[];
+ /** Aggregated summary counts by severity */
+ summary: DiffSummary;
+ /** Recommended semver bump based on highest severity change */
+ suggestedBump: SuggestedBump;
+}
+
+/**
+ * Severity of a lint diagnostic.
+ */
+export type LintSeverity = 'error' | 'warning';
+
+/**
+ * A single lint issue found in a spec.
+ */
+export interface LintIssue {
+ /** Location in spec (JSON Pointer path or line:col) */
+ path: string;
+ /** Human-readable issue description */
+ message: string;
+ /** Rule identifier if available (e.g., "operation-operationId") */
+ rule?: string;
+ /** Issue severity */
+ severity: LintSeverity;
+}
+
+/**
+ * Result of linting a spec file.
+ */
+export interface LintResult {
+ /** Contract name from config */
+ contract: string;
+ /** Absolute path to the spec file that was linted */
+ specPath: string;
+ /** List of error-level issues (cause lint failure) */
+ errors: LintIssue[];
+ /** List of warning-level issues (informational) */
+ warnings: LintIssue[];
+}
+
+/**
+ * Options for linter functions.
+ */
+export interface LintOptions {
+ /** Custom ruleset configuration */
+ ruleset?: string;
+ /** Additional tool-specific options */
+ [key: string]: unknown;
+}
+
+/**
+ * Function signature for linter implementations.
+ *
+ * @param specPath - Absolute path to the spec file to lint
+ * @param options - Optional linter configuration
+ * @returns Promise resolving to lint results
+ */
+export type LintFn = (specPath: string, options?: LintOptions) => Promise;
+
+/**
+ * Options for differ functions.
+ */
+export interface DiffOptions {
+ /** Include metadata-only (patch) changes in results */
+ includeMetadata?: boolean;
+ /** Additional tool-specific options */
+ [key: string]: unknown;
+}
+
+/**
+ * Function signature for differ implementations.
+ *
+ * @param oldSpecPath - Absolute path to the old (baseline) spec
+ * @param newSpecPath - Absolute path to the new (current) spec
+ * @param options - Optional differ configuration
+ * @returns Promise resolving to diff results
+ */
+export type DiffFn = (
+ oldSpecPath: string,
+ newSpecPath: string,
+ options?: DiffOptions
+) => Promise;
+
+/**
+ * All possible structural change types for classification.
+ *
+ * @remarks
+ * These categories are used internally by differs to classify raw changes
+ * before mapping to severity levels.
+ */
+export type ChangeType =
+ // Property-level changes
+ | 'property-added'
+ | 'property-removed'
+ | 'required-added'
+ | 'required-removed'
+ // Type-level changes
+ | 'type-changed'
+ | 'type-narrowed'
+ | 'type-widened'
+ // Enum-level changes
+ | 'enum-value-added'
+ | 'enum-value-removed'
+ | 'enum-added'
+ | 'enum-removed'
+ // Constraint-level changes
+ | 'constraint-tightened'
+ | 'constraint-loosened'
+ | 'format-changed'
+ | 'format-added'
+ | 'format-removed'
+ // Object-level changes
+ | 'additional-properties-denied'
+ | 'additional-properties-allowed'
+ | 'additional-properties-changed'
+ | 'property-names-changed'
+ | 'dependent-required-added'
+ | 'dependent-required-removed'
+ | 'dependent-schemas-changed'
+ | 'unevaluated-properties-changed'
+ // Array-level changes
+ | 'items-changed'
+ | 'min-items-increased'
+ | 'max-items-decreased'
+ | 'min-contains-changed'
+ | 'max-contains-changed'
+ | 'unevaluated-items-changed'
+ // Ref-level changes
+ | 'ref-target-changed'
+ // Metadata-level changes (patch)
+ | 'description-changed'
+ | 'title-changed'
+ | 'default-changed'
+ | 'examples-changed'
+ // Annotation changes (patch per Strands API)
+ | 'deprecated-changed'
+ | 'read-only-changed'
+ | 'write-only-changed'
+ // Content keyword changes (patch per Strands API)
+ | 'content-encoding-changed'
+ | 'content-media-type-changed'
+ | 'content-schema-changed'
+ // Granular composition changes (replacing generic composition-changed)
+ | 'anyof-option-added'
+ | 'anyof-option-removed'
+ | 'oneof-option-added'
+ | 'oneof-option-removed'
+ | 'allof-member-added'
+ | 'allof-member-removed'
+ | 'not-schema-changed'
+ | 'if-then-else-changed'
+ // Legacy composition (for backward compat)
+ | 'composition-changed'
+ // OpenAPI structural changes
+ | 'path-added'
+ | 'path-removed'
+ | 'operation-added'
+ | 'operation-removed'
+ | 'parameter-added'
+ | 'parameter-required-added'
+ | 'parameter-removed'
+ | 'parameter-required-changed'
+ | 'parameter-schema-changed'
+ | 'request-body-added'
+ | 'request-body-removed'
+ | 'response-added'
+ | 'response-removed'
+ | 'response-schema-changed'
+ | 'security-changed'
+ | 'server-changed'
+ // Catch-all for unrecognized changes
+ | 'unknown-change';
+
+/**
+ * Raw change detected by a differ before severity classification.
+ *
+ * @remarks
+ * This is an internal type used by differ implementations.
+ * Raw changes are classified into {@link Change} with severity.
+ */
+export interface RawChange {
+ /** JSON Pointer path to the change location */
+ path: string;
+ /** Structural change type for classification */
+ type: ChangeType;
+ /** Value in old spec (undefined if added) */
+ oldValue?: unknown;
+ /** Value in new spec (undefined if removed) */
+ newValue?: unknown;
+}
+
+/**
+ * Mapping from change types to their severity classification.
+ *
+ * @remarks
+ * This constant provides the default classification rules aligned with Strands API.
+ * Breaking changes cause major bumps, non-breaking cause minor, etc.
+ */
+export const CHANGE_TYPE_SEVERITY: Record = {
+ // Breaking changes (major)
+ 'property-removed': 'breaking',
+ 'required-added': 'breaking',
+ 'type-changed': 'breaking',
+ 'type-narrowed': 'breaking',
+ 'enum-value-removed': 'breaking',
+ 'enum-added': 'breaking',
+ 'constraint-tightened': 'breaking',
+ 'additional-properties-denied': 'breaking',
+ 'items-changed': 'breaking',
+ 'min-items-increased': 'breaking',
+ 'max-items-decreased': 'breaking',
+ 'ref-target-changed': 'breaking',
+ 'dependent-required-added': 'breaking',
+ // Composition breaking changes (per Strands API)
+ 'anyof-option-added': 'breaking',
+ 'oneof-option-added': 'breaking',
+ 'allof-member-added': 'breaking',
+ 'not-schema-changed': 'breaking',
+
+ // Non-breaking changes (minor)
+ 'property-added': 'non-breaking',
+ 'required-removed': 'non-breaking',
+ 'type-widened': 'non-breaking',
+ 'enum-value-added': 'non-breaking',
+ 'enum-removed': 'non-breaking',
+ 'constraint-loosened': 'non-breaking',
+ 'additional-properties-allowed': 'non-breaking',
+ 'additional-properties-changed': 'non-breaking',
+ 'dependent-required-removed': 'non-breaking',
+ // Composition non-breaking changes (per Strands API)
+ 'anyof-option-removed': 'non-breaking',
+ 'oneof-option-removed': 'non-breaking',
+ 'allof-member-removed': 'non-breaking',
+
+ // Patch-level changes (per Strands API - format is annotation)
+ 'format-added': 'patch',
+ 'format-removed': 'patch',
+ 'format-changed': 'patch',
+ 'description-changed': 'patch',
+ 'title-changed': 'patch',
+ 'default-changed': 'patch',
+ 'examples-changed': 'patch',
+ // Annotation changes (patch per Strands API)
+ 'deprecated-changed': 'patch',
+ 'read-only-changed': 'patch',
+ 'write-only-changed': 'patch',
+ // Content keyword changes (patch per Strands API)
+ 'content-encoding-changed': 'patch',
+ 'content-media-type-changed': 'patch',
+ 'content-schema-changed': 'patch',
+
+ // Requires manual review (unknown)
+ 'property-names-changed': 'unknown',
+ 'dependent-schemas-changed': 'unknown',
+ 'unevaluated-properties-changed': 'unknown',
+ 'unevaluated-items-changed': 'unknown',
+ 'min-contains-changed': 'unknown',
+ 'max-contains-changed': 'unknown',
+ 'if-then-else-changed': 'unknown',
+ 'composition-changed': 'unknown',
+ // OpenAPI structural changes
+ 'path-removed': 'breaking',
+ 'operation-removed': 'breaking',
+ 'parameter-added': 'non-breaking',
+ 'parameter-required-added': 'breaking',
+ 'parameter-removed': 'breaking',
+ 'parameter-required-changed': 'breaking',
+ 'request-body-added': 'breaking',
+ 'response-removed': 'breaking',
+ 'security-changed': 'breaking',
+ 'path-added': 'non-breaking',
+ 'operation-added': 'non-breaking',
+ 'request-body-removed': 'non-breaking',
+ 'response-added': 'non-breaking',
+ 'server-changed': 'non-breaking',
+ 'parameter-schema-changed': 'unknown',
+ 'response-schema-changed': 'unknown',
+ 'unknown-change': 'unknown',
+};
+
+/**
+ * Type guard to check if a value is a valid ChangeSeverity.
+ *
+ * @param value - The value to check
+ * @returns True if the value is a valid ChangeSeverity
+ */
+export function isChangeSeverity(value: unknown): value is ChangeSeverity {
+ return (
+ typeof value === 'string' && ['breaking', 'non-breaking', 'patch', 'unknown'].includes(value)
+ );
+}
+
+/**
+ * Type guard to check if a value is a valid ChangeType.
+ *
+ * @param value - The value to check
+ * @returns True if the value is a valid ChangeType
+ */
+export function isChangeType(value: unknown): value is ChangeType {
+ return typeof value === 'string' && value in CHANGE_TYPE_SEVERITY;
+}
diff --git a/packages/types/index.ts b/packages/types/index.ts
new file mode 100644
index 0000000..c23ccde
--- /dev/null
+++ b/packages/types/index.ts
@@ -0,0 +1,3 @@
+export * from './config.js';
+export * from './governance.js';
+export * from './versioning.js';
diff --git a/packages/types/package.json b/packages/types/package.json
new file mode 100644
index 0000000..d596426
--- /dev/null
+++ b/packages/types/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@contractual/types",
+ "private": false,
+ "version": "0.1.0-dev.5",
+ "description": "TypeScript type definitions for Contractual - schema contract lifecycle orchestration",
+ "license": "MIT",
+ "type": "module",
+ "sideEffects": false,
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.js"
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/contractual-dev/contractual.git",
+ "directory": "packages/types"
+ },
+ "homepage": "https://contractual.dev",
+ "bugs": {
+ "url": "https://github.com/contractual-dev/contractual/issues"
+ },
+ "keywords": [
+ "contractual",
+ "types",
+ "typescript",
+ "openapi",
+ "json-schema",
+ "asyncapi",
+ "odcs",
+ "schema",
+ "contract"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "scripts": {
+ "prebuild": "pnpm rimraf dist",
+ "build": "tsc -p tsconfig.build.json",
+ "typecheck": "tsc -p tsconfig.build.json --noEmit"
+ },
+ "files": [
+ "dist"
+ ],
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ }
+}
diff --git a/packages/types/tsconfig.build.json b/packages/types/tsconfig.build.json
new file mode 100644
index 0000000..973b05e
--- /dev/null
+++ b/packages/types/tsconfig.build.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "composite": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true
+ }
+}
diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json
new file mode 100644
index 0000000..5e75f83
--- /dev/null
+++ b/packages/types/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "./dist",
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "emitDecoratorMetadata": false,
+ "experimentalDecorators": false
+ },
+ "include": ["*.ts"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/packages/types/versioning.ts b/packages/types/versioning.ts
new file mode 100644
index 0000000..8afb1cc
--- /dev/null
+++ b/packages/types/versioning.ts
@@ -0,0 +1,206 @@
+import type { DiffResult, LintResult } from './governance.js';
+
+/**
+ * Semver bump type for version increments.
+ */
+export type BumpType = 'major' | 'minor' | 'patch';
+
+/**
+ * Version entry for a single contract in the history.
+ */
+export interface VersionEntry {
+ /** Semver version string (e.g., "1.2.0") */
+ version: string;
+ /** ISO 8601 timestamp of when this version was released */
+ released: string;
+ /** Changeset filenames that contributed to this version */
+ changesets?: string[];
+}
+
+/**
+ * Contents of versions.json file for a single contract.
+ *
+ * @example
+ * ```json
+ * {
+ * "current": "1.2.0",
+ * "versions": [
+ * { "version": "0.1.0", "released": "2026-02-01T10:00:00Z" },
+ * { "version": "1.0.0", "released": "2026-02-05T14:30:00Z", "changesets": ["brave-tigers-fly"] }
+ * ]
+ * }
+ * ```
+ */
+export interface ContractVersionsFile {
+ /** Current (latest) version */
+ current: string;
+ /** History of all versions */
+ versions: VersionEntry[];
+}
+
+/**
+ * Simple version entry used in the legacy VersionsFile format.
+ * Contains only the essential version tracking fields.
+ */
+export interface SimpleVersionEntry {
+ /** Current version */
+ version: string;
+ /** ISO 8601 timestamp of last release */
+ released: string;
+}
+
+/**
+ * Aggregated versions.json file mapping contract names to their version info.
+ *
+ * @remarks
+ * This is the legacy format used for simple version tracking.
+ * For richer history tracking, use ContractVersionsFile per contract.
+ */
+export interface VersionsFile {
+ [contractName: string]: SimpleVersionEntry;
+}
+
+/**
+ * Parsed changeset file data.
+ *
+ * @example
+ * ```markdown
+ * ---
+ * "orders-api": major
+ * "order-schema": minor
+ * ---
+ *
+ * ## orders-api
+ *
+ * **Breaking changes:**
+ * - Removed endpoint GET /orders/{id}/details
+ * ```
+ */
+export interface ChangesetFile {
+ /** Filename without path (e.g., "brave-tigers-fly.md") */
+ filename: string;
+ /** Full path to the changeset file */
+ path: string;
+ /** Map of contract name to bump type */
+ bumps: Record;
+ /** Markdown body with change descriptions */
+ body: string;
+}
+
+/**
+ * Result of applying a version bump to a single contract.
+ */
+export interface BumpResult {
+ /** Contract name */
+ contract: string;
+ /** Version before bump */
+ oldVersion: string;
+ /** Version after bump */
+ newVersion: string;
+ /** Type of bump applied */
+ bumpType: BumpType;
+ /** Markdown section describing changes from changeset body */
+ changes: string;
+}
+
+/**
+ * Result of the `contractual version` command.
+ */
+export interface VersionCommandResult {
+ /** All version bumps that were applied */
+ bumps: BumpResult[];
+ /** Filenames of changesets that were consumed */
+ consumedChangesets: string[];
+ /** Updated changelog content (if generated) */
+ changelog?: string;
+}
+
+/**
+ * Result of the `contractual lint` command.
+ */
+export interface LintCommandResult {
+ /** Whether all contracts passed linting (no errors) */
+ success: boolean;
+ /** Individual lint results per contract */
+ results: LintResult[];
+ /** Total error count across all contracts */
+ errorCount: number;
+ /** Total warning count across all contracts */
+ warningCount: number;
+}
+
+/**
+ * Result of the `contractual breaking` command.
+ */
+export interface BreakingCommandResult {
+ /** Whether any breaking changes were detected */
+ hasBreaking: boolean;
+ /** Individual diff results per contract */
+ results: DiffResult[];
+ /** Suggested overall bump type based on highest severity */
+ suggestedBump: BumpType | 'none';
+}
+
+/**
+ * Result of the `contractual changeset` command.
+ */
+export interface ChangesetCommandResult {
+ /** Whether a changeset was created */
+ created: boolean;
+ /** Path to the created changeset file (if created) */
+ path?: string;
+ /** Filename of the created changeset (if created) */
+ filename?: string;
+ /** Map of contract names to their detected bump types */
+ bumps: Record;
+}
+
+/**
+ * Result of the `contractual status` command.
+ */
+export interface StatusCommandResult {
+ /** Current contract versions */
+ versions: Record;
+ /** Pending changesets awaiting consumption */
+ pendingChangesets: string[];
+ /** Predicted version bumps from pending changesets */
+ pendingBumps: Record;
+ /** Whether there are uncommitted spec changes without changesets */
+ hasUncommittedChanges: boolean;
+}
+
+/**
+ * Type guard to check if a value is a valid BumpType.
+ *
+ * @param value - The value to check
+ * @returns True if the value is a valid BumpType
+ */
+export function isBumpType(value: unknown): value is BumpType {
+ return (
+ typeof value === 'string' &&
+ ['major', 'minor', 'patch'].includes(value)
+ );
+}
+
+/**
+ * Pre-release state stored in .contractual/pre.json
+ *
+ * @example
+ * ```json
+ * {
+ * "tag": "beta",
+ * "enteredAt": "2026-03-10T10:00:00Z",
+ * "initialVersions": {
+ * "orders-api": "1.2.0"
+ * }
+ * }
+ * ```
+ */
+export interface PreReleaseState {
+ /** Pre-release tag (e.g., "alpha", "beta", "rc") */
+ tag: string;
+ /** ISO 8601 timestamp when pre-release mode was entered */
+ enteredAt: string;
+ /** Versions of contracts when pre-release mode was entered */
+ initialVersions: Record;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cc4a422..71a4cfe 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,1327 +5,1512 @@ settings:
excludeLinksFromLockfile: false
importers:
-
.:
- dependencies:
- '@manypkg/cli':
- specifier: ^0.21.4
- version: 0.21.4
+ devDependencies:
'@types/node':
specifier: ^22.10.2
- version: 22.10.7
+ version: 22.19.11
'@typescript-eslint/eslint-plugin':
specifier: ^6.7.5
version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)
'@typescript-eslint/parser':
specifier: ^6.7.5
version: 6.21.0(eslint@8.57.1)(typescript@5.7.3)
- '@vitest/coverage-c8':
- specifier: ^0.33.0
- version: 0.33.0(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))
'@vitest/coverage-v8':
- specifier: 3.0.3
- version: 3.0.3(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))
- braces:
- specifier: 3.0.3
- version: 3.0.3
+ specifier: ^3.0.3
+ version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(yaml@2.8.2))
eslint:
specifier: ^8.57.0
version: 8.57.1
eslint-config-prettier:
specifier: ^9.0.0
- version: 9.1.0(eslint@8.57.1)
+ version: 9.1.2(eslint@8.57.1)
eslint-import-resolver-typescript:
specifier: ^3.6.1
- version: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1)
+ version: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
eslint-plugin-import:
specifier: ^2.29.1
- version: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1)
+ version: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
eslint-plugin-prettier:
specifier: ^5.0.1
- version: 5.2.3(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2)
- follow-redirects:
- specifier: 1.15.6
- version: 1.15.6
- ip:
- specifier: 2.0.1
- version: 2.0.1
+ version: 5.5.5(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.8.1)
+ husky:
+ specifier: ^8.0.3
+ version: 8.0.3
+ json-schema-typed:
+ specifier: ^8.0.2
+ version: 8.0.2
lerna:
- specifier: ^7.3.1
- version: 7.4.2(encoding@0.1.13)
+ specifier: ^8.2.3
+ version: 8.2.4(@types/node@22.19.11)(encoding@0.1.13)
lint-staged:
specifier: ^14.0.1
version: 14.0.1(enquirer@2.3.6)
- madge:
- specifier: ^7.0.0
- version: 7.0.0(typescript@5.7.3)
- micromatch:
- specifier: 4.0.8
- version: 4.0.8
prettier:
specifier: ^3.2.5
- version: 3.4.2
+ version: 3.8.1
rimraf:
specifier: ^5.0.5
version: 5.0.10
- rxjs:
- specifier: ^7.8.1
- version: 7.8.1
- tar:
- specifier: 6.2.0
- version: 6.2.0
- ts-jest:
- specifier: ^29.1.3
- version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)))(typescript@5.7.3)
- ts-node:
- specifier: ^10.9.1
- version: 10.9.2(@types/node@22.10.7)(typescript@5.7.3)
typescript:
specifier: ~5.7.2
version: 5.7.3
vitest:
specifier: ^3.0.3
- version: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ version: 3.2.4(@types/node@22.19.11)(yaml@2.8.2)
+ yaml:
+ specifier: ^2.8.2
+ version: 2.8.2
+
+ packages/changesets:
+ dependencies:
+ '@contractual/types':
+ specifier: workspace:*
+ version: link:../types
+ semver:
+ specifier: ^7.7.1
+ version: 7.7.4
+ yaml:
+ specifier: ^2.7.0
+ version: 2.8.2
devDependencies:
- husky:
- specifier: ^8.0.3
- version: 8.0.3
+ '@types/semver':
+ specifier: ^7.5.8
+ version: 7.7.1
packages/cli:
dependencies:
- '@contractual/generators.contract':
+ '@contractual/changesets':
specifier: workspace:*
- version: link:../generators/contract
- '@contractual/generators.diff':
+ version: link:../changesets
+ '@contractual/governance':
specifier: workspace:*
- version: link:../generators/diff
- '@contractual/generators.spec':
+ version: link:../governance
+ '@contractual/types':
specifier: workspace:*
- version: link:../generators/spec
+ version: link:../types
+ '@inquirer/prompts':
+ specifier: ^8.1.0
+ version: 8.1.0(@types/node@22.19.11)
+ ajv:
+ specifier: ^8.17.1
+ version: 8.18.0
+ ajv-formats:
+ specifier: ^3.0.1
+ version: 3.0.1(ajv@8.18.0)
chalk:
specifier: ^5.4.1
- version: 5.4.1
+ version: 5.6.2
commander:
specifier: ^12.1.0
version: 12.1.0
- inquirer:
- specifier: ^12.3.2
- version: 12.3.2(@types/node@22.10.7)
+ fast-glob:
+ specifier: ^3.3.3
+ version: 3.3.3
ora:
specifier: ^8.1.1
- version: 8.1.1
+ version: 8.2.0
+ yaml:
+ specifier: ^2.7.0
+ version: 2.8.2
devDependencies:
- '@vitest/coverage-c8':
- specifier: ^0.33.0
- version: 0.33.0(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))
+ '@vitest/coverage-v8':
+ specifier: ^3.0.0
+ version: 3.2.4(vitest@3.2.4(@types/node@22.19.11)(yaml@2.8.2))
vitest:
specifier: ^3.0.3
- version: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ version: 3.2.4(@types/node@22.19.11)(yaml@2.8.2)
- packages/contract:
+ packages/differs.core:
dependencies:
- '@ts-rest/core':
- specifier: ^3.51.0
- version: 3.51.0(@types/node@22.10.7)(zod@3.24.1)
- axios:
- specifier: ^1.7.9
- version: 1.7.9
- zod:
- specifier: ^3.24.1
- version: 3.24.1
-
- packages/generators/contract:
- dependencies:
- '@apidevtools/swagger-parser':
- specifier: ^10.1.1
- version: 10.1.1(openapi-types@12.1.3)
- chalk:
- specifier: ^5.4.1
- version: 5.4.1
- handlebars:
- specifier: ^4.7.8
- version: 4.7.8
- openapi-types:
- specifier: ^12.1.3
- version: 12.1.3
- openapi-zod-client:
- specifier: ^1.18.2
- version: 1.18.2
- openapi3-ts:
- specifier: ^4.4.0
- version: 4.4.0
+ '@contractual/types':
+ specifier: workspace:*
+ version: link:../types
devDependencies:
- ora:
- specifier: ^8.1.1
- version: 8.1.1
- typescript:
- specifier: ~5.7.2
- version: 5.7.3
+ rimraf:
+ specifier: ^5.0.5
+ version: 5.0.10
- packages/generators/diff:
+ packages/differs.json-schema:
dependencies:
- chalk:
- specifier: ^5.4.1
- version: 5.4.1
- openapi-diff:
- specifier: ^0.23.7
- version: 0.23.7(openapi-types@12.1.3)
- openapi-types:
- specifier: ^12.1.3
- version: 12.1.3
- semver:
- specifier: ^7.6.3
- version: 7.6.3
- table:
- specifier: ^6.9.0
- version: 6.9.0
+ '@contractual/differs.core':
+ specifier: workspace:*
+ version: link:../differs.core
+ '@contractual/types':
+ specifier: workspace:*
+ version: link:../types
devDependencies:
- '@types/semver':
- specifier: ^7.5.8
- version: 7.5.8
- '@vitest/coverage-c8':
- specifier: ^0.33.0
- version: 0.33.0(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))
- typescript:
- specifier: ~5.7.2
- version: 5.7.3
+ rimraf:
+ specifier: ^5.0.5
+ version: 5.0.10
vitest:
specifier: ^3.0.3
- version: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ version: 3.2.4(@types/node@22.19.11)(yaml@2.8.2)
- packages/generators/spec:
+ packages/differs.openapi:
dependencies:
- '@contractual/generators.diff':
+ '@contractual/differs.core':
specifier: workspace:*
- version: link:../diff
- '@typespec/compiler':
- specifier: ^0.63.0
- version: 0.63.0
- '@typespec/http':
- specifier: ^0.63.0
- version: 0.63.0(@typespec/compiler@0.63.0)
- '@typespec/openapi':
- specifier: ^0.63.0
- version: 0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))
- '@typespec/openapi3':
- specifier: ^0.63.0
- version: 0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))(@typespec/openapi@0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0)))(@typespec/versioning@0.63.0(@typespec/compiler@0.63.0))
- '@typespec/rest':
- specifier: ^0.63.1
- version: 0.63.1(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))
- '@typespec/versioning':
- specifier: ^0.63.0
- version: 0.63.0(@typespec/compiler@0.63.0)
- semver:
- specifier: ^7.6.3
- version: 7.6.3
- yaml:
- specifier: ^2.7.0
- version: 2.7.0
+ version: link:../differs.core
+ '@contractual/types':
+ specifier: workspace:*
+ version: link:../types
+ '@redocly/openapi-core':
+ specifier: ^1.0.0
+ version: 1.34.6
devDependencies:
- '@types/semver':
- specifier: ^7.5.8
- version: 7.5.8
- chalk:
- specifier: ^5.4.1
- version: 5.4.1
- inquirer:
- specifier: ^12.3.2
- version: 12.3.2(@types/node@22.10.7)
- openapi-types:
- specifier: ^12.1.3
- version: 12.1.3
- ora:
- specifier: ^8.1.1
- version: 8.1.1
- typescript:
- specifier: ~5.7.2
- version: 5.7.3
-
-packages:
-
- '@ampproject/remapping@2.3.0':
- resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
- engines: {node: '>=6.0.0'}
-
- '@apidevtools/json-schema-ref-parser@11.7.2':
- resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==}
- engines: {node: '>= 16'}
-
- '@apidevtools/json-schema-ref-parser@9.0.9':
- resolution: {integrity: sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==}
-
- '@apidevtools/json-schema-ref-parser@9.1.2':
- resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==}
-
- '@apidevtools/openapi-schemas@2.1.0':
- resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
- engines: {node: '>=10'}
-
- '@apidevtools/swagger-methods@3.0.2':
- resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
-
- '@apidevtools/swagger-parser@10.0.3':
- resolution: {integrity: sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==}
- peerDependencies:
- openapi-types: '>=7'
-
- '@apidevtools/swagger-parser@10.1.1':
- resolution: {integrity: sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==}
- peerDependencies:
- openapi-types: '>=7'
-
- '@babel/code-frame@7.25.9':
- resolution: {integrity: sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/code-frame@7.26.2':
- resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.26.5':
- resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.26.0':
- resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.26.5':
- resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.26.5':
- resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.25.9':
- resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.26.0':
- resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-plugin-utils@7.26.5':
- resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-string-parser@7.25.9':
- resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.25.9':
- resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.25.9':
- resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
- engines: {node: '>=6.9.0'}
+ rimraf:
+ specifier: ^5.0.5
+ version: 5.0.10
- '@babel/helpers@7.26.0':
- resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
- engines: {node: '>=6.9.0'}
+ packages/governance:
+ dependencies:
+ '@contractual/differs.json-schema':
+ specifier: workspace:*
+ version: link:../differs.json-schema
+ '@contractual/differs.openapi':
+ specifier: workspace:*
+ version: link:../differs.openapi
+ '@contractual/types':
+ specifier: workspace:*
+ version: link:../types
+ ajv:
+ specifier: ^8.17.1
+ version: 8.18.0
+ ajv-formats:
+ specifier: ^3.0.1
+ version: 3.0.1(ajv@8.18.0)
+ devDependencies:
+ '@redocly/openapi-core':
+ specifier: ^1.0.0
+ version: 1.34.6
- '@babel/highlight@7.25.9':
- resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==}
- engines: {node: '>=6.9.0'}
+ packages/types: {}
- '@babel/parser@7.26.5':
- resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==}
- engines: {node: '>=6.0.0'}
+packages:
+ '@ampproject/remapping@2.3.0':
+ resolution:
+ {
+ integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==,
+ }
+ engines: { node: '>=6.0.0' }
+
+ '@babel/code-frame@7.29.0':
+ resolution:
+ {
+ integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==,
+ }
+ engines: { node: '>=6.9.0' }
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution:
+ {
+ integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==,
+ }
+ engines: { node: '>=6.9.0' }
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution:
+ {
+ integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==,
+ }
+ engines: { node: '>=6.9.0' }
+
+ '@babel/parser@7.29.0':
+ resolution:
+ {
+ integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==,
+ }
+ engines: { node: '>=6.0.0' }
hasBin: true
- '@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-bigint@7.8.3':
- resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-static-block@7.14.5':
- resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-attributes@7.26.0':
- resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-jsx@7.25.9':
- resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5':
- resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-typescript@7.25.9':
- resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/runtime@7.26.0':
- resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/template@7.25.9':
- resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.26.5':
- resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.26.5':
- resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==}
- engines: {node: '>=6.9.0'}
-
- '@bcoe/v8-coverage@0.2.3':
- resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ '@babel/types@7.29.0':
+ resolution:
+ {
+ integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==,
+ }
+ engines: { node: '>=6.9.0' }
'@bcoe/v8-coverage@1.0.2':
- resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
- engines: {node: '>=18'}
-
- '@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
-
- '@dependents/detective-less@4.1.0':
- resolution: {integrity: sha512-KrkT6qO5NxqNfy68sBl6CTSoJ4SNDIS5iQArkibhlbGU4LaDukZ3q2HIkh8aUKDio6o4itU4xDR7t82Y2eP1Bg==}
- engines: {node: '>=14'}
-
- '@esbuild/aix-ppc64@0.24.2':
- resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==,
+ }
+ engines: { node: '>=18' }
+
+ '@emnapi/core@1.8.1':
+ resolution:
+ {
+ integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==,
+ }
+
+ '@emnapi/runtime@1.8.1':
+ resolution:
+ {
+ integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==,
+ }
+
+ '@emnapi/wasi-threads@1.1.0':
+ resolution:
+ {
+ integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==,
+ }
+
+ '@esbuild/aix-ppc64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==,
+ }
+ engines: { node: '>=18' }
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.24.2':
- resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
- engines: {node: '>=18'}
+ '@esbuild/android-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.24.2':
- resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
- engines: {node: '>=18'}
+ '@esbuild/android-arm@0.27.3':
+ resolution:
+ {
+ integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==,
+ }
+ engines: { node: '>=18' }
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.24.2':
- resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
- engines: {node: '>=18'}
+ '@esbuild/android-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.24.2':
- resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
- engines: {node: '>=18'}
+ '@esbuild/darwin-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.24.2':
- resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
- engines: {node: '>=18'}
+ '@esbuild/darwin-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.24.2':
- resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
- engines: {node: '>=18'}
+ '@esbuild/freebsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.24.2':
- resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
- engines: {node: '>=18'}
+ '@esbuild/freebsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.24.2':
- resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
- engines: {node: '>=18'}
+ '@esbuild/linux-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.24.2':
- resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
- engines: {node: '>=18'}
+ '@esbuild/linux-arm@0.27.3':
+ resolution:
+ {
+ integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==,
+ }
+ engines: { node: '>=18' }
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.24.2':
- resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
- engines: {node: '>=18'}
+ '@esbuild/linux-ia32@0.27.3':
+ resolution:
+ {
+ integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==,
+ }
+ engines: { node: '>=18' }
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.24.2':
- resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
- engines: {node: '>=18'}
+ '@esbuild/linux-loong64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==,
+ }
+ engines: { node: '>=18' }
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.24.2':
- resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
- engines: {node: '>=18'}
+ '@esbuild/linux-mips64el@0.27.3':
+ resolution:
+ {
+ integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==,
+ }
+ engines: { node: '>=18' }
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.24.2':
- resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
- engines: {node: '>=18'}
+ '@esbuild/linux-ppc64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==,
+ }
+ engines: { node: '>=18' }
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.24.2':
- resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
- engines: {node: '>=18'}
+ '@esbuild/linux-riscv64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==,
+ }
+ engines: { node: '>=18' }
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.24.2':
- resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
- engines: {node: '>=18'}
+ '@esbuild/linux-s390x@0.27.3':
+ resolution:
+ {
+ integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==,
+ }
+ engines: { node: '>=18' }
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.24.2':
- resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
- engines: {node: '>=18'}
+ '@esbuild/linux-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.24.2':
- resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
- engines: {node: '>=18'}
+ '@esbuild/netbsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.24.2':
- resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
- engines: {node: '>=18'}
+ '@esbuild/netbsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.24.2':
- resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
- engines: {node: '>=18'}
+ '@esbuild/openbsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.24.2':
- resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
- engines: {node: '>=18'}
+ '@esbuild/openbsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [openbsd]
- '@esbuild/sunos-x64@0.24.2':
- resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
- engines: {node: '>=18'}
+ '@esbuild/openharmony-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.24.2':
- resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
- engines: {node: '>=18'}
+ '@esbuild/win32-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==,
+ }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.24.2':
- resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
- engines: {node: '>=18'}
+ '@esbuild/win32-ia32@0.27.3':
+ resolution:
+ {
+ integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==,
+ }
+ engines: { node: '>=18' }
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.24.2':
- resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
- engines: {node: '>=18'}
+ '@esbuild/win32-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==,
+ }
+ engines: { node: '>=18' }
cpu: [x64]
os: [win32]
- '@eslint-community/eslint-utils@4.4.1':
- resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint-community/eslint-utils@4.9.1':
+ resolution:
+ {
+ integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- '@eslint-community/regexpp@4.12.1':
- resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
- engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ '@eslint-community/regexpp@4.12.2':
+ resolution:
+ {
+ integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==,
+ }
+ engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 }
'@eslint/eslintrc@2.1.4':
- resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
'@eslint/js@8.57.1':
- resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
- '@gar/promisify@1.1.3':
- resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
+ resolution:
+ {
+ integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
'@humanwhocodes/config-array@0.13.0':
- resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
- engines: {node: '>=10.10.0'}
- deprecated: Use @eslint/config-array instead
+ resolution:
+ {
+ integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==,
+ }
+ engines: { node: '>=10.10.0' }
'@humanwhocodes/module-importer@1.0.1':
- resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
- engines: {node: '>=12.22'}
-
- '@humanwhocodes/momoa@2.0.4':
- resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
- engines: {node: '>=10.10.0'}
+ resolution:
+ {
+ integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==,
+ }
+ engines: { node: '>=12.22' }
'@humanwhocodes/object-schema@2.0.3':
- resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
- deprecated: Use @eslint/object-schema instead
+ resolution:
+ {
+ integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==,
+ }
'@hutson/parse-repository-url@3.0.2':
- resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==}
- engines: {node: '>=6.9.0'}
-
- '@inquirer/checkbox@4.0.6':
- resolution: {integrity: sha512-PgP35JfmGjHU0LSXOyRew0zHuA9N6OJwOlos1fZ20b7j8ISeAdib3L+n0jIxBtX958UeEpte6xhG/gxJ5iUqMw==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==,
+ }
+ engines: { node: '>=6.9.0' }
+
+ '@inquirer/ansi@2.0.2':
+ resolution:
+ {
+ integrity: sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
+
+ '@inquirer/checkbox@5.0.3':
+ resolution:
+ {
+ integrity: sha512-xtQP2eXMFlOcAhZ4ReKP2KZvDIBb1AnCfZ81wWXG3DXLVH0f0g4obE0XDPH+ukAEMRcZT0kdX2AS1jrWGXbpxw==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/confirm@5.1.3':
- resolution: {integrity: sha512-fuF9laMmHoOgWapF9h9hv6opA5WvmGFHsTYGCmuFxcghIhEhb3dN0CdQR4BUMqa2H506NCj8cGX4jwMsE4t6dA==}
- engines: {node: '>=18'}
+ '@inquirer/confirm@6.0.3':
+ resolution:
+ {
+ integrity: sha512-lyEvibDFL+NA5R4xl8FUmNhmu81B+LDL9L/MpKkZlQDJZXzG8InxiqYxiAlQYa9cqLLhYqKLQwZqXmSTqCLjyw==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/core@10.1.4':
- resolution: {integrity: sha512-5y4/PUJVnRb4bwWY67KLdebWOhOc7xj5IP2J80oWXa64mVag24rwQ1VAdnj7/eDY/odhguW0zQ1Mp1pj6fO/2w==}
- engines: {node: '>=18'}
-
- '@inquirer/editor@4.2.3':
- resolution: {integrity: sha512-S9KnIOJuTZpb9upeRSBBhoDZv7aSV3pG9TECrBj0f+ZsFwccz886hzKBrChGrXMJwd4NKY+pOA9Vy72uqnd6Eg==}
- engines: {node: '>=18'}
+ '@inquirer/core@11.1.0':
+ resolution:
+ {
+ integrity: sha512-+jD/34T1pK8M5QmZD/ENhOfXdl9Zr+BrQAUc5h2anWgi7gggRq15ZbiBeLoObj0TLbdgW7TAIQRU2boMc9uOKQ==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/expand@4.0.6':
- resolution: {integrity: sha512-TRTfi1mv1GeIZGyi9PQmvAaH65ZlG4/FACq6wSzs7Vvf1z5dnNWsAAXBjWMHt76l+1hUY8teIqJFrWBk5N6gsg==}
- engines: {node: '>=18'}
+ '@inquirer/editor@5.0.3':
+ resolution:
+ {
+ integrity: sha512-wYyQo96TsAqIciP/r5D3cFeV8h4WqKQ/YOvTg5yOfP2sqEbVVpbxPpfV3LM5D0EP4zUI3EZVHyIUIllnoIa8OQ==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/figures@1.0.9':
- resolution: {integrity: sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==}
- engines: {node: '>=18'}
-
- '@inquirer/input@4.1.3':
- resolution: {integrity: sha512-zeo++6f7hxaEe7OjtMzdGZPHiawsfmCZxWB9X1NpmYgbeoyerIbWemvlBxxl+sQIlHC0WuSAG19ibMq3gbhaqQ==}
- engines: {node: '>=18'}
+ '@inquirer/expand@5.0.3':
+ resolution:
+ {
+ integrity: sha512-2oINvuL27ujjxd95f6K2K909uZOU2x1WiAl7Wb1X/xOtL8CgQ1kSxzykIr7u4xTkXkXOAkCuF45T588/YKee7w==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/number@3.0.6':
- resolution: {integrity: sha512-xO07lftUHk1rs1gR0KbqB+LJPhkUNkyzV/KhH+937hdkMazmAYHLm1OIrNKpPelppeV1FgWrgFDjdUD8mM+XUg==}
- engines: {node: '>=18'}
+ '@inquirer/external-editor@1.0.3':
+ resolution:
+ {
+ integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==,
+ }
+ engines: { node: '>=18' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/password@4.0.6':
- resolution: {integrity: sha512-QLF0HmMpHZPPMp10WGXh6F+ZPvzWE7LX6rNoccdktv/Rov0B+0f+eyXkAcgqy5cH9V+WSpbLxu2lo3ysEVK91w==}
- engines: {node: '>=18'}
+ '@inquirer/external-editor@2.0.2':
+ resolution:
+ {
+ integrity: sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/prompts@7.2.3':
- resolution: {integrity: sha512-hzfnm3uOoDySDXfDNOm9usOuYIaQvTgKp/13l1uJoe6UNY+Zpcn2RYt0jXz3yA+yemGHvDOxVzqWl3S5sQq53Q==}
- engines: {node: '>=18'}
+ '@inquirer/figures@2.0.2':
+ resolution:
+ {
+ integrity: sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
+
+ '@inquirer/input@5.0.3':
+ resolution:
+ {
+ integrity: sha512-4R0TdWl53dtp79Vs6Df2OHAtA2FVNqya1hND1f5wjHWxZJxwDMSNB1X5ADZJSsQKYAJ5JHCTO+GpJZ42mK0Otw==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/rawlist@4.0.6':
- resolution: {integrity: sha512-QoE4s1SsIPx27FO4L1b1mUjVcoHm1pWE/oCmm4z/Hl+V1Aw5IXl8FYYzGmfXaBT0l/sWr49XmNSiq7kg3Kd/Lg==}
- engines: {node: '>=18'}
+ '@inquirer/number@4.0.3':
+ resolution:
+ {
+ integrity: sha512-TjQLe93GGo5snRlu83JxE38ZPqj5ZVggL+QqqAF2oBA5JOJoxx25GG3EGH/XN/Os5WOmKfO8iLVdCXQxXRZIMQ==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/search@3.0.6':
- resolution: {integrity: sha512-eFZ2hiAq0bZcFPuFFBmZEtXU1EarHLigE+ENCtpO+37NHCl4+Yokq1P/d09kUblObaikwfo97w+0FtG/EXl5Ng==}
- engines: {node: '>=18'}
+ '@inquirer/password@5.0.3':
+ resolution:
+ {
+ integrity: sha512-rCozGbUMAHedTeYWEN8sgZH4lRCdgG/WinFkit6ZPsp8JaNg2T0g3QslPBS5XbpORyKP/I+xyBO81kFEvhBmjA==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/select@4.0.6':
- resolution: {integrity: sha512-yANzIiNZ8fhMm4NORm+a74+KFYHmf7BZphSOBovIzYPVLquseTGEkU5l2UTnBOf5k0VLmTgPighNDLE9QtbViQ==}
- engines: {node: '>=18'}
+ '@inquirer/prompts@8.1.0':
+ resolution:
+ {
+ integrity: sha512-LsZMdKcmRNF5LyTRuZE5nWeOjganzmN3zwbtNfcs6GPh3I2TsTtF1UYZlbxVfhxd+EuUqLGs/Lm3Xt4v6Az1wA==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@inquirer/type@3.0.2':
- resolution: {integrity: sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==}
- engines: {node: '>=18'}
+ '@inquirer/rawlist@5.1.0':
+ resolution:
+ {
+ integrity: sha512-yUCuVh0jW026Gr2tZlG3kHignxcrLKDR3KBp+eUgNz+BAdSeZk0e18yt2gyBr+giYhj/WSIHCmPDOgp1mT2niQ==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
'@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@isaacs/cliui@8.0.2':
- resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
- engines: {node: '>=12'}
-
- '@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
-
- '@istanbuljs/schema@0.1.3':
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
-
- '@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@inquirer/search@4.0.3':
+ resolution:
+ {
+ integrity: sha512-lzqVw0YwuKYetk5VwJ81Ba+dyVlhseHPx9YnRKQgwXdFS0kEavCz2gngnNhnMIxg8+j1N/rUl1t5s1npwa7bqg==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ '@types/node': '>=18'
peerDependenciesMeta:
- node-notifier:
+ '@types/node':
optional: true
- '@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect-utils@29.7.0':
- resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@inquirer/select@5.0.3':
+ resolution:
+ {
+ integrity: sha512-M+ynbwS0ecQFDYMFrQrybA0qL8DV0snpc4kKevCCNaTpfghsRowRY7SlQBeIYNzHqXtiiz4RG9vTOeb/udew7w==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ '@types/node': '>=18'
peerDependenciesMeta:
- node-notifier:
+ '@types/node':
optional: true
- '@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@inquirer/type@4.0.2':
+ resolution:
+ {
+ integrity: sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==,
+ }
+ engines: { node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0' }
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
- '@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@isaacs/cliui@8.0.2':
+ resolution:
+ {
+ integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==,
+ }
+ engines: { node: '>=12' }
+
+ '@isaacs/string-locale-compare@1.1.0':
+ resolution:
+ {
+ integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==,
+ }
- '@jest/types@29.6.3':
- resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@istanbuljs/schema@0.1.3':
+ resolution:
+ {
+ integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==,
+ }
+ engines: { node: '>=8' }
- '@jridgewell/gen-mapping@0.3.8':
- resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
- engines: {node: '>=6.0.0'}
+ '@jest/schemas@29.6.3':
+ resolution:
+ {
+ integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==,
+ }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution:
+ {
+ integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==,
+ }
'@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/set-array@1.2.1':
- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.5.0':
- resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
-
- '@jridgewell/trace-mapping@0.3.25':
- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
-
- '@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
-
- '@jsdevtools/ono@7.1.3':
- resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
-
- '@lerna/child-process@7.4.2':
- resolution: {integrity: sha512-je+kkrfcvPcwL5Tg8JRENRqlbzjdlZXyaR88UcnCdNW0AJ1jX9IfHRys1X7AwSroU2ug8ESNC+suoBw1vX833Q==}
- engines: {node: '>=16.0.0'}
-
- '@lerna/create@7.4.2':
- resolution: {integrity: sha512-1wplFbQ52K8E/unnqB0Tq39Z4e+NEoNrpovEnl6GpsTUrC6WDp8+w0Le2uCBV0hXyemxChduCkLz4/y1H1wTeg==}
- engines: {node: '>=16.0.0'}
-
- '@liuli-util/fs-extra@0.1.0':
- resolution: {integrity: sha512-eaAyDyMGT23QuRGbITVY3SOJff3G9ekAAyGqB9joAnTBmqvFN+9a1FazOdO70G6IUqgpKV451eBHYSRcOJ/FNQ==}
-
- '@manypkg/cli@0.21.4':
- resolution: {integrity: sha512-EACxxb+c/t6G0l1FrlyewZeBnyR5V1cLkXjnBfsay5TN1UgbilFpG6POglzn+lVJet9NqnEKe3RLHABzkIDZ0Q==}
- engines: {node: '>=14.18.0'}
- hasBin: true
-
- '@manypkg/find-root@2.2.3':
- resolution: {integrity: sha512-jtEZKczWTueJYHjGpxU3KJQ08Gsrf4r6Q2GjmPp/RGk5leeYAA1eyDADSAF+KVCsQ6EwZd/FMcOFCoMhtqdCtQ==}
- engines: {node: '>=14.18.0'}
-
- '@manypkg/get-packages@2.2.2':
- resolution: {integrity: sha512-3+Zd8kLZmsyJFmWTBtY0MAuCErI7yKB2cjMBlujvSVKZ2R/BMXi0kjCXu2dtRlSq/ML86t1FkumT0yreQ3n8OQ==}
- engines: {node: '>=14.18.0'}
-
- '@manypkg/tools@1.1.2':
- resolution: {integrity: sha512-3lBouSuF7CqlseLB+FKES0K4FQ02JrbEoRtJhxnsyB1s5v4AP03gsoohN8jp7DcOImhaR9scYdztq3/sLfk/qQ==}
- engines: {node: '>=14.18.0'}
+ resolution:
+ {
+ integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==,
+ }
+ engines: { node: '>=6.0.0' }
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution:
+ {
+ integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==,
+ }
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution:
+ {
+ integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==,
+ }
+
+ '@lerna/create@8.2.4':
+ resolution:
+ {
+ integrity: sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==,
+ }
+ engines: { node: '>=18.0.0' }
+
+ '@napi-rs/wasm-runtime@0.2.12':
+ resolution:
+ {
+ integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==,
+ }
+
+ '@napi-rs/wasm-runtime@0.2.4':
+ resolution:
+ {
+ integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==,
+ }
'@nodelib/fs.scandir@2.1.5':
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==,
+ }
+ engines: { node: '>= 8' }
'@nodelib/fs.stat@2.0.5':
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==,
+ }
+ engines: { node: '>= 8' }
'@nodelib/fs.walk@1.2.8':
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==,
+ }
+ engines: { node: '>= 8' }
'@nolyfill/is-core-module@1.0.39':
- resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
- engines: {node: '>=12.4.0'}
-
- '@npmcli/fs@2.1.2':
- resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==,
+ }
+ engines: { node: '>=12.4.0' }
+
+ '@npmcli/agent@2.2.2':
+ resolution:
+ {
+ integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@npmcli/arborist@7.5.4':
+ resolution:
+ {
+ integrity: sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+ hasBin: true
'@npmcli/fs@3.1.1':
- resolution: {integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@npmcli/git@4.1.0':
- resolution: {integrity: sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ '@npmcli/git@5.0.8':
+ resolution:
+ {
+ integrity: sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
'@npmcli/installed-package-contents@2.1.0':
- resolution: {integrity: sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
hasBin: true
- '@npmcli/move-file@2.0.1':
- resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This functionality has been moved to @npmcli/fs
+ '@npmcli/map-workspaces@3.0.6':
+ resolution:
+ {
+ integrity: sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ '@npmcli/metavuln-calculator@7.1.1':
+ resolution:
+ {
+ integrity: sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@npmcli/name-from-folder@2.0.0':
+ resolution:
+ {
+ integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
'@npmcli/node-gyp@3.0.0':
- resolution: {integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@npmcli/promise-spawn@6.0.2':
- resolution: {integrity: sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@npmcli/run-script@6.0.2':
- resolution: {integrity: sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@nrwl/devkit@16.10.0':
- resolution: {integrity: sha512-fRloARtsDQoQgQ7HKEy0RJiusg/HSygnmg4gX/0n/Z+SUS+4KoZzvHjXc6T5ZdEiSjvLypJ+HBM8dQzIcVACPQ==}
-
- '@nrwl/tao@16.10.0':
- resolution: {integrity: sha512-QNAanpINbr+Pod6e1xNgFbzK1x5wmZl+jMocgiEFXZ67KHvmbD6MAQQr0MMz+GPhIu7EE4QCTLTyCEMlAG+K5Q==}
- hasBin: true
-
- '@nx/devkit@16.10.0':
- resolution: {integrity: sha512-IvKQqRJFDDiaj33SPfGd3ckNHhHi6ceEoqCbAP4UuMXOPPVOX6H0KVk+9tknkPb48B7jWIw6/AgOeWkBxPRO5w==}
+ resolution:
+ {
+ integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ '@npmcli/package-json@5.2.0':
+ resolution:
+ {
+ integrity: sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@npmcli/promise-spawn@7.0.2':
+ resolution:
+ {
+ integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@npmcli/query@3.1.0':
+ resolution:
+ {
+ integrity: sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ '@npmcli/redact@2.0.1':
+ resolution:
+ {
+ integrity: sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@npmcli/run-script@8.1.0':
+ resolution:
+ {
+ integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@nx/devkit@20.8.2':
+ resolution:
+ {
+ integrity: sha512-rr9p2/tZDQivIpuBUpZaFBK6bZ+b5SAjZk75V4tbCUqGW3+5OPuVvBPm+X+7PYwUF6rwSpewxkjWNeGskfCe+Q==,
+ }
peerDependencies:
- nx: '>= 15 <= 17'
-
- '@nx/nx-darwin-arm64@16.10.0':
- resolution: {integrity: sha512-YF+MIpeuwFkyvM5OwgY/rTNRpgVAI/YiR0yTYCZR+X3AAvP775IVlusNgQ3oedTBRUzyRnI4Tknj1WniENFsvQ==}
- engines: {node: '>= 10'}
+ nx: '>= 19 <= 21'
+
+ '@nx/nx-darwin-arm64@20.8.2':
+ resolution:
+ {
+ integrity: sha512-t+bmCn6sRPNGU6hnSyWNvbQYA/KgsxGZKYlaCLRwkNhI2akModcBUqtktJzCKd1XHDqs6EkEFBWjFr8/kBEkSg==,
+ }
+ engines: { node: '>= 10' }
cpu: [arm64]
os: [darwin]
- '@nx/nx-darwin-x64@16.10.0':
- resolution: {integrity: sha512-ypi6YxwXgb0kg2ixKXE3pwf5myVNUgWf1CsV5OzVccCM8NzheMO51KDXTDmEpXdzUsfT0AkO1sk5GZeCjhVONg==}
- engines: {node: '>= 10'}
+ '@nx/nx-darwin-x64@20.8.2':
+ resolution:
+ {
+ integrity: sha512-pt/wmDLM31Es8/EzazlyT5U+ou2l60rfMNFGCLqleHEQ0JUTc0KWnOciBLbHIQFiPsCQZJFEKyfV5V/ncePmmw==,
+ }
+ engines: { node: '>= 10' }
cpu: [x64]
os: [darwin]
- '@nx/nx-freebsd-x64@16.10.0':
- resolution: {integrity: sha512-UeEYFDmdbbDkTQamqvtU8ibgu5jQLgFF1ruNb/U4Ywvwutw2d4ruOMl2e0u9hiNja9NFFAnDbvzrDcMo7jYqYw==}
- engines: {node: '>= 10'}
+ '@nx/nx-freebsd-x64@20.8.2':
+ resolution:
+ {
+ integrity: sha512-joZxFbgJfkHkB9uMIJr73Gpnm9pnpvr0XKGbWC409/d2x7q1qK77tKdyhGm+A3+kaZFwstNVPmCUtUwJYyU6LA==,
+ }
+ engines: { node: '>= 10' }
cpu: [x64]
os: [freebsd]
- '@nx/nx-linux-arm-gnueabihf@16.10.0':
- resolution: {integrity: sha512-WV3XUC2DB6/+bz1sx+d1Ai9q2Cdr+kTZRN50SOkfmZUQyEBaF6DRYpx/a4ahhxH3ktpNfyY8Maa9OEYxGCBkQA==}
- engines: {node: '>= 10'}
+ '@nx/nx-linux-arm-gnueabihf@20.8.2':
+ resolution:
+ {
+ integrity: sha512-98O/qsxn4vIMPY/FyzvmVrl7C5yFhCUVk0/4PF+PA2SvtQ051L1eMRY6bq/lb69qfN6szJPZ41PG5mPx0NeLZw==,
+ }
+ engines: { node: '>= 10' }
cpu: [arm]
os: [linux]
- '@nx/nx-linux-arm64-gnu@16.10.0':
- resolution: {integrity: sha512-aWIkOUw995V3ItfpAi5FuxQ+1e9EWLS1cjWM1jmeuo+5WtaKToJn5itgQOkvSlPz+HSLgM3VfXMvOFALNk125g==}
- engines: {node: '>= 10'}
+ '@nx/nx-linux-arm64-gnu@20.8.2':
+ resolution:
+ {
+ integrity: sha512-h6a+HxwfSpxsi4KpxGgPh9GDBmD2E+XqGCdfYpobabxqEBvlnIlJyuDhlRR06cTWpuNXHpRdrVogmV6m/YbtDg==,
+ }
+ engines: { node: '>= 10' }
cpu: [arm64]
os: [linux]
- '@nx/nx-linux-arm64-musl@16.10.0':
- resolution: {integrity: sha512-uO6Gg+irqpVcCKMcEPIQcTFZ+tDI02AZkqkP7koQAjniLEappd8DnUBSQdcn53T086pHpdc264X/ZEpXFfrKWQ==}
- engines: {node: '>= 10'}
+ '@nx/nx-linux-arm64-musl@20.8.2':
+ resolution:
+ {
+ integrity: sha512-4Ev+jM0VAxDHV/dFgMXjQTCXS4I8W4oMe7FSkXpG8RUn6JK659DC8ExIDPoGIh+Cyqq6r6mw1CSia+ciQWICWQ==,
+ }
+ engines: { node: '>= 10' }
cpu: [arm64]
os: [linux]
- '@nx/nx-linux-x64-gnu@16.10.0':
- resolution: {integrity: sha512-134PW/u/arNFAQKpqMJniC7irbChMPz+W+qtyKPAUXE0XFKPa7c1GtlI/wK2dvP9qJDZ6bKf0KtA0U/m2HMUOA==}
- engines: {node: '>= 10'}
+ '@nx/nx-linux-x64-gnu@20.8.2':
+ resolution:
+ {
+ integrity: sha512-nR0ev+wxu+nQYRd7bhqggOxK7UfkV6h+Ko1mumUFyrM5GvPpz/ELhjJFSnMcOkOMcvH0b6G5uTBJvN1XWCkbmg==,
+ }
+ engines: { node: '>= 10' }
cpu: [x64]
os: [linux]
- '@nx/nx-linux-x64-musl@16.10.0':
- resolution: {integrity: sha512-q8sINYLdIJxK/iUx9vRk5jWAWb/2O0PAbOJFwv4qkxBv4rLoN7y+otgCZ5v0xfx/zztFgk/oNY4lg5xYjIso2Q==}
- engines: {node: '>= 10'}
+ '@nx/nx-linux-x64-musl@20.8.2':
+ resolution:
+ {
+ integrity: sha512-ost41l5yc2aq2Gc9bMMpaPi/jkXqbXEMEPHrxWKuKmaek3K2zbVDQzvBBNcQKxf/mlCsrqN4QO0mKYSRRqag5A==,
+ }
+ engines: { node: '>= 10' }
cpu: [x64]
os: [linux]
- '@nx/nx-win32-arm64-msvc@16.10.0':
- resolution: {integrity: sha512-moJkL9kcqxUdJSRpG7dET3UeLIciwrfP08mzBQ12ewo8K8FzxU8ZUsTIVVdNrwt01CXOdXoweGfdQLjJ4qTURA==}
- engines: {node: '>= 10'}
+ '@nx/nx-win32-arm64-msvc@20.8.2':
+ resolution:
+ {
+ integrity: sha512-0SEOqT/daBG5WtM9vOGilrYaAuf1tiALdrFavY62+/arXYxXemUKmRI5qoKDTnvoLMBGkJs6kxhMO5b7aUXIvQ==,
+ }
+ engines: { node: '>= 10' }
cpu: [arm64]
os: [win32]
- '@nx/nx-win32-x64-msvc@16.10.0':
- resolution: {integrity: sha512-5iV2NKZnzxJwZZ4DM5JVbRG/nkhAbzEskKaLBB82PmYGKzaDHuMHP1lcPoD/rtYMlowZgNA/RQndfKvPBPwmXA==}
- engines: {node: '>= 10'}
+ '@nx/nx-win32-x64-msvc@20.8.2':
+ resolution:
+ {
+ integrity: sha512-iIsY+tVqes/NOqTbJmggL9Juie/iaDYlWgXA9IUv88FE9thqWKhVj4/tCcPjsOwzD+1SVna3YISEEFsx5UV4ew==,
+ }
+ engines: { node: '>= 10' }
cpu: [x64]
os: [win32]
- '@octokit/auth-token@3.0.4':
- resolution: {integrity: sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==}
- engines: {node: '>= 14'}
-
- '@octokit/core@4.2.4':
- resolution: {integrity: sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==}
- engines: {node: '>= 14'}
-
- '@octokit/endpoint@7.0.6':
- resolution: {integrity: sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==}
- engines: {node: '>= 14'}
-
- '@octokit/graphql@5.0.6':
- resolution: {integrity: sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==}
- engines: {node: '>= 14'}
-
- '@octokit/openapi-types@18.1.1':
- resolution: {integrity: sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==}
+ '@octokit/auth-token@4.0.0':
+ resolution:
+ {
+ integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/core@5.2.2':
+ resolution:
+ {
+ integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/endpoint@9.0.6':
+ resolution:
+ {
+ integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/graphql@7.1.1':
+ resolution:
+ {
+ integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/openapi-types@24.2.0':
+ resolution:
+ {
+ integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==,
+ }
'@octokit/plugin-enterprise-rest@6.0.1':
- resolution: {integrity: sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==}
-
- '@octokit/plugin-paginate-rest@6.1.2':
- resolution: {integrity: sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==}
- engines: {node: '>= 14'}
+ resolution:
+ {
+ integrity: sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==,
+ }
+
+ '@octokit/plugin-paginate-rest@11.4.4-cjs.2':
+ resolution:
+ {
+ integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==,
+ }
+ engines: { node: '>= 18' }
peerDependencies:
- '@octokit/core': '>=4'
-
- '@octokit/plugin-request-log@1.0.4':
- resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==}
+ '@octokit/core': '5'
+
+ '@octokit/plugin-request-log@4.0.1':
+ resolution:
+ {
+ integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==,
+ }
+ engines: { node: '>= 18' }
peerDependencies:
- '@octokit/core': '>=3'
-
- '@octokit/plugin-rest-endpoint-methods@7.2.3':
- resolution: {integrity: sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==}
- engines: {node: '>= 14'}
+ '@octokit/core': '5'
+
+ '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1':
+ resolution:
+ {
+ integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==,
+ }
+ engines: { node: '>= 18' }
peerDependencies:
- '@octokit/core': '>=3'
-
- '@octokit/request-error@3.0.3':
- resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==}
- engines: {node: '>= 14'}
-
- '@octokit/request@6.2.8':
- resolution: {integrity: sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==}
- engines: {node: '>= 14'}
-
- '@octokit/rest@19.0.11':
- resolution: {integrity: sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==}
- engines: {node: '>= 14'}
-
- '@octokit/tsconfig@1.0.2':
- resolution: {integrity: sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==}
-
- '@octokit/types@10.0.0':
- resolution: {integrity: sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==}
-
- '@octokit/types@9.3.2':
- resolution: {integrity: sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==}
-
- '@parcel/watcher@2.0.4':
- resolution: {integrity: sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==}
- engines: {node: '>= 10.0.0'}
+ '@octokit/core': ^5
+
+ '@octokit/request-error@5.1.1':
+ resolution:
+ {
+ integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/request@8.4.1':
+ resolution:
+ {
+ integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/rest@20.1.2':
+ resolution:
+ {
+ integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==,
+ }
+ engines: { node: '>= 18' }
+
+ '@octokit/types@13.10.0':
+ resolution:
+ {
+ integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==,
+ }
'@pkgjs/parseargs@0.11.0':
- resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
- engines: {node: '>=14'}
-
- '@pkgr/core@0.1.1':
- resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
- engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
-
- '@pnpm/config.env-replace@1.1.0':
- resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
- engines: {node: '>=12.22.0'}
-
- '@pnpm/network.ca-file@1.0.2':
- resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==}
- engines: {node: '>=12.22.0'}
-
- '@pnpm/npm-conf@2.3.1':
- resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==}
- engines: {node: '>=12'}
-
- '@readme/better-ajv-errors@1.6.0':
- resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==}
- engines: {node: '>=14'}
- peerDependencies:
- ajv: 4.11.8 - 8
-
- '@readme/json-schema-ref-parser@1.2.0':
- resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==}
-
- '@readme/openapi-parser@2.6.0':
- resolution: {integrity: sha512-pyFJXezWj9WI1O+gdp95CoxfY+i+Uq3kKk4zXIFuRAZi9YnHpHOpjumWWr67wkmRTw19Hskh9spyY0Iyikf3fA==}
- engines: {node: '>=18'}
- peerDependencies:
- openapi-types: '>=7'
-
- '@readme/openapi-schemas@3.1.0':
- resolution: {integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==}
- engines: {node: '>=18'}
-
- '@rollup/rollup-android-arm-eabi@4.31.0':
- resolution: {integrity: sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==}
+ resolution:
+ {
+ integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==,
+ }
+ engines: { node: '>=14' }
+
+ '@pkgr/core@0.2.9':
+ resolution:
+ {
+ integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==,
+ }
+ engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
+
+ '@redocly/ajv@8.17.4':
+ resolution:
+ {
+ integrity: sha512-BieiCML/IgP6x99HZByJSt7fJE4ipgzO7KAFss92Bs+PEI35BhY7vGIysFXLT+YmS7nHtQjZjhOQyPPEf7xGHA==,
+ }
+
+ '@redocly/config@0.22.2':
+ resolution:
+ {
+ integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==,
+ }
+
+ '@redocly/openapi-core@1.34.6':
+ resolution:
+ {
+ integrity: sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw==,
+ }
+ engines: { node: '>=18.17.0', npm: '>=9.5.0' }
+
+ '@rollup/rollup-android-arm-eabi@4.57.1':
+ resolution:
+ {
+ integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==,
+ }
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.31.0':
- resolution: {integrity: sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==}
+ '@rollup/rollup-android-arm64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==,
+ }
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.31.0':
- resolution: {integrity: sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==}
+ '@rollup/rollup-darwin-arm64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==,
+ }
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.31.0':
- resolution: {integrity: sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==}
+ '@rollup/rollup-darwin-x64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==,
+ }
cpu: [x64]
os: [darwin]
- '@rollup/rollup-freebsd-arm64@4.31.0':
- resolution: {integrity: sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==}
+ '@rollup/rollup-freebsd-arm64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==,
+ }
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.31.0':
- resolution: {integrity: sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==}
+ '@rollup/rollup-freebsd-x64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==,
+ }
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-linux-arm-gnueabihf@4.31.0':
- resolution: {integrity: sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
+ resolution:
+ {
+ integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==,
+ }
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.31.0':
- resolution: {integrity: sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==}
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
+ resolution:
+ {
+ integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==,
+ }
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.31.0':
- resolution: {integrity: sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==}
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==,
+ }
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.31.0':
- resolution: {integrity: sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==}
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
+ resolution:
+ {
+ integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==,
+ }
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-loongarch64-gnu@4.31.0':
- resolution: {integrity: sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==}
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==,
+ }
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.31.0':
- resolution: {integrity: sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==}
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
+ resolution:
+ {
+ integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==,
+ }
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==,
+ }
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
+ resolution:
+ {
+ integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==,
+ }
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.31.0':
- resolution: {integrity: sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==}
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==,
+ }
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.31.0':
- resolution: {integrity: sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==}
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
+ resolution:
+ {
+ integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==,
+ }
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==,
+ }
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.31.0':
- resolution: {integrity: sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==}
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==,
+ }
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.31.0':
- resolution: {integrity: sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==}
+ '@rollup/rollup-linux-x64-musl@4.57.1':
+ resolution:
+ {
+ integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==,
+ }
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.31.0':
- resolution: {integrity: sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==}
+ '@rollup/rollup-openbsd-x64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==,
+ }
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.57.1':
+ resolution:
+ {
+ integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==,
+ }
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
+ resolution:
+ {
+ integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==,
+ }
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.31.0':
- resolution: {integrity: sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==}
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
+ resolution:
+ {
+ integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==,
+ }
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.31.0':
- resolution: {integrity: sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==}
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
+ resolution:
+ {
+ integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==,
+ }
cpu: [x64]
os: [win32]
- '@rtsao/scc@1.1.0':
- resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
-
- '@sigstore/bundle@1.1.0':
- resolution: {integrity: sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@sigstore/protobuf-specs@0.2.1':
- resolution: {integrity: sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@sigstore/sign@1.0.0':
- resolution: {integrity: sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
+ resolution:
+ {
+ integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==,
+ }
+ cpu: [x64]
+ os: [win32]
- '@sigstore/tuf@1.0.3':
- resolution: {integrity: sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ '@rtsao/scc@1.1.0':
+ resolution:
+ {
+ integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==,
+ }
+
+ '@sigstore/bundle@2.3.2':
+ resolution:
+ {
+ integrity: sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@sigstore/core@1.1.0':
+ resolution:
+ {
+ integrity: sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@sigstore/protobuf-specs@0.3.3':
+ resolution:
+ {
+ integrity: sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==,
+ }
+ engines: { node: ^18.17.0 || >=20.5.0 }
+
+ '@sigstore/sign@2.3.2':
+ resolution:
+ {
+ integrity: sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@sigstore/tuf@2.3.4':
+ resolution:
+ {
+ integrity: sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@sigstore/verify@1.2.1':
+ resolution:
+ {
+ integrity: sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
'@sinclair/typebox@0.27.8':
- resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
-
- '@sindresorhus/is@5.6.0':
- resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
- engines: {node: '>=14.16'}
-
- '@sindresorhus/merge-streams@2.3.0':
- resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
- engines: {node: '>=18'}
-
- '@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
-
- '@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
-
- '@szmarczak/http-timer@5.0.1':
- resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
- engines: {node: '>=14.16'}
-
- '@tootallnate/once@2.0.0':
- resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
- engines: {node: '>= 10'}
-
- '@ts-rest/core@3.51.0':
- resolution: {integrity: sha512-v6lnWEcpZj1UgN9wb84XQ+EORP1QEtncFumoXMJjno5ZUV6vdjKze3MYcQN0C6vjBpIJPQEaI/gab2jr4/0KzQ==}
- peerDependencies:
- '@types/node': ^18.18.7 || >=20.8.4
- zod: ^3.22.3
- peerDependenciesMeta:
- '@types/node':
- optional: true
- zod:
- optional: true
-
- '@tsconfig/node10@1.0.11':
- resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
-
- '@tsconfig/node12@1.0.11':
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
-
- '@tsconfig/node14@1.0.3':
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
-
- '@tsconfig/node16@1.0.4':
- resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
-
- '@tufjs/canonical-json@1.0.0':
- resolution: {integrity: sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@tufjs/models@1.0.4':
- resolution: {integrity: sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- '@types/babel__core@7.20.5':
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
-
- '@types/babel__generator@7.6.8':
- resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
-
- '@types/babel__template@7.4.4':
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
-
- '@types/babel__traverse@7.20.6':
- resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
-
- '@types/estree@1.0.6':
- resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
-
- '@types/fs-extra@9.0.13':
- resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
-
- '@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
-
- '@types/http-cache-semantics@4.0.4':
- resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
-
- '@types/istanbul-lib-coverage@2.0.6':
- resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
-
- '@types/istanbul-lib-report@3.0.3':
- resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
-
- '@types/istanbul-reports@3.0.4':
- resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+ resolution:
+ {
+ integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==,
+ }
+
+ '@tufjs/canonical-json@2.0.0':
+ resolution:
+ {
+ integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@tufjs/models@2.0.1':
+ resolution:
+ {
+ integrity: sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ '@tybys/wasm-util@0.10.1':
+ resolution:
+ {
+ integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==,
+ }
+
+ '@tybys/wasm-util@0.9.0':
+ resolution:
+ {
+ integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==,
+ }
+
+ '@types/chai@5.2.3':
+ resolution:
+ {
+ integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==,
+ }
+
+ '@types/deep-eql@4.0.2':
+ resolution:
+ {
+ integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==,
+ }
+
+ '@types/estree@1.0.8':
+ resolution:
+ {
+ integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==,
+ }
'@types/json-schema@7.0.15':
- resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ resolution:
+ {
+ integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==,
+ }
'@types/json5@0.0.29':
- resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+ resolution:
+ {
+ integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==,
+ }
'@types/minimatch@3.0.5':
- resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
+ resolution:
+ {
+ integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==,
+ }
'@types/minimist@1.2.5':
- resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
+ resolution:
+ {
+ integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==,
+ }
- '@types/node@22.10.7':
- resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==}
+ '@types/node@22.19.11':
+ resolution:
+ {
+ integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==,
+ }
'@types/normalize-package-data@2.4.4':
- resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
-
- '@types/semver@6.2.7':
- resolution: {integrity: sha512-blctEWbzUFzQx799RZjzzIdBJOXmE37YYEyDtKkx5Dg+V7o/zyyAxLPiI98A2jdTtDgxZleMdfV+7p8WbRJ1OQ==}
+ resolution:
+ {
+ integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==,
+ }
- '@types/semver@7.5.8':
- resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
-
- '@types/stack-utils@2.0.3':
- resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
-
- '@types/yargs-parser@21.0.3':
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
-
- '@types/yargs@17.0.33':
- resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+ '@types/semver@7.7.1':
+ resolution:
+ {
+ integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==,
+ }
'@typescript-eslint/eslint-plugin@6.21.0':
- resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
eslint: ^7.0.0 || ^8.0.0
@@ -1335,8 +1520,11 @@ packages:
optional: true
'@typescript-eslint/parser@6.21.0':
- resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
@@ -1345,12 +1533,18 @@ packages:
optional: true
'@typescript-eslint/scope-manager@6.21.0':
- resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
'@typescript-eslint/type-utils@6.21.0':
- resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
@@ -1358,26 +1552,19 @@ packages:
typescript:
optional: true
- '@typescript-eslint/types@5.62.0':
- resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
'@typescript-eslint/types@6.21.0':
- resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
- engines: {node: ^16.0.0 || >=18.0.0}
-
- '@typescript-eslint/typescript-estree@5.62.0':
- resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- peerDependencies:
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
+ resolution:
+ {
+ integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
'@typescript-eslint/typescript-estree@6.21.0':
- resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -1385,726 +1572,1035 @@ packages:
optional: true
'@typescript-eslint/utils@6.21.0':
- resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
- '@typescript-eslint/visitor-keys@5.62.0':
- resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
'@typescript-eslint/visitor-keys@6.21.0':
- resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
- engines: {node: ^16.0.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==,
+ }
+ engines: { node: ^16.0.0 || >=18.0.0 }
+
+ '@ungap/structured-clone@1.3.0':
+ resolution:
+ {
+ integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==,
+ }
+
+ '@unrs/resolver-binding-android-arm-eabi@1.11.1':
+ resolution:
+ {
+ integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==,
+ }
+ cpu: [arm]
+ os: [android]
- '@typespec/compiler@0.63.0':
- resolution: {integrity: sha512-cC3YniwbFghn1fASX3r1IgNjMrwaY4gmzznkHT4f/NxE+HK4XoXWn4EG7287QgVMCaHUykzJCIfW9k7kIleW5A==}
- engines: {node: '>=18.0.0'}
- hasBin: true
+ '@unrs/resolver-binding-android-arm64@1.11.1':
+ resolution:
+ {
+ integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==,
+ }
+ cpu: [arm64]
+ os: [android]
- '@typespec/http@0.63.0':
- resolution: {integrity: sha512-SYVbBmLPAPdWZfdMs0QlbpTnFREDnkINu2FR+0kRX12qzbRgpRbLsdhg59qx4TfKoh4IAPgSV+Fq84w7BWGsyQ==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- '@typespec/compiler': ~0.63.0
- '@typespec/streams': ~0.63.0
- peerDependenciesMeta:
- '@typespec/streams':
- optional: true
+ '@unrs/resolver-binding-darwin-arm64@1.11.1':
+ resolution:
+ {
+ integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==,
+ }
+ cpu: [arm64]
+ os: [darwin]
- '@typespec/openapi3@0.63.0':
- resolution: {integrity: sha512-HC8VeakPznXNn7euAyAxUFNsOcfSzM8tQwYPNUMWs0qGJqGgb6vjf5rShQmfgrCe5Y6zcMM2PPBuxaFV3xXYLw==}
- engines: {node: '>=18.0.0'}
- hasBin: true
- peerDependencies:
- '@typespec/compiler': ~0.63.0
- '@typespec/http': ~0.63.0
- '@typespec/openapi': ~0.63.0
- '@typespec/versioning': ~0.63.0
- '@typespec/xml': '*'
- peerDependenciesMeta:
- '@typespec/xml':
- optional: true
+ '@unrs/resolver-binding-darwin-x64@1.11.1':
+ resolution:
+ {
+ integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==,
+ }
+ cpu: [x64]
+ os: [darwin]
- '@typespec/openapi@0.63.0':
- resolution: {integrity: sha512-/KzR60mj3P/LnNWd/QfH0KTN/If4+mjrsWNSB7/uab6c8Qu/lNsGlZDkmWq4EFiwBR7VmpdFz9FP7d/m3O+tGw==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- '@typespec/compiler': ~0.63.0
- '@typespec/http': ~0.63.0
+ '@unrs/resolver-binding-freebsd-x64@1.11.1':
+ resolution:
+ {
+ integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==,
+ }
+ cpu: [x64]
+ os: [freebsd]
- '@typespec/rest@0.63.1':
- resolution: {integrity: sha512-RQbTM+HGjCaNIWC0v72m5ulnuvLjuRigb7pH4QeRCvFtGPHos+WBv5SImkGrbYx3353OGR8dIi7lWe7aNwiDcQ==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- '@typespec/compiler': ~0.63.0
- '@typespec/http': ~0.63.0
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
+ resolution:
+ {
+ integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==,
+ }
+ cpu: [arm]
+ os: [linux]
- '@typespec/versioning@0.63.0':
- resolution: {integrity: sha512-BPvmPL+g20yEmSA8XRfbIHdToNOjssq4QfwOU6D7kKLLXnZHFb1hmuwW0tf0Wa/lYgoaUC60ONAeoXgNT1ZOIQ==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- '@typespec/compiler': ~0.63.0
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
+ resolution:
+ {
+ integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==,
+ }
+ cpu: [arm]
+ os: [linux]
- '@ungap/structured-clone@1.2.1':
- resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==}
+ '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
+ resolution:
+ {
+ integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==,
+ }
+ cpu: [arm64]
+ os: [linux]
- '@vitest/coverage-c8@0.33.0':
- resolution: {integrity: sha512-DaF1zJz4dcOZS4k/neiQJokmOWqsGXwhthfmUdPGorXIQHjdPvV6JQSYhQDI41MyI8c+IieQUdIDs5XAMHtDDw==}
- deprecated: v8 coverage is moved to @vitest/coverage-v8 package
- peerDependencies:
- vitest: '>=0.30.0 <1'
+ '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
+ resolution:
+ {
+ integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==,
+ }
+ cpu: [arm64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
+ resolution:
+ {
+ integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==,
+ }
+ cpu: [ppc64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
+ resolution:
+ {
+ integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==,
+ }
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
+ resolution:
+ {
+ integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==,
+ }
+ cpu: [riscv64]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
+ resolution:
+ {
+ integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==,
+ }
+ cpu: [s390x]
+ os: [linux]
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
+ resolution:
+ {
+ integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==,
+ }
+ cpu: [x64]
+ os: [linux]
- '@vitest/coverage-v8@3.0.3':
- resolution: {integrity: sha512-uVbJ/xhImdNtzPnLyxCZJMTeTIYdgcC2nWtBBBpR1H6z0w8m7D+9/zrDIx2nNxgMg9r+X8+RY2qVpUDeW2b3nw==}
+ '@unrs/resolver-binding-linux-x64-musl@1.11.1':
+ resolution:
+ {
+ integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==,
+ }
+ cpu: [x64]
+ os: [linux]
+
+ '@unrs/resolver-binding-wasm32-wasi@1.11.1':
+ resolution:
+ {
+ integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==,
+ }
+ engines: { node: '>=14.0.0' }
+ cpu: [wasm32]
+
+ '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
+ resolution:
+ {
+ integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==,
+ }
+ cpu: [arm64]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
+ resolution:
+ {
+ integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==,
+ }
+ cpu: [ia32]
+ os: [win32]
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
+ resolution:
+ {
+ integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==,
+ }
+ cpu: [x64]
+ os: [win32]
+
+ '@vitest/coverage-v8@3.2.4':
+ resolution:
+ {
+ integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==,
+ }
peerDependencies:
- '@vitest/browser': 3.0.3
- vitest: 3.0.3
+ '@vitest/browser': 3.2.4
+ vitest: 3.2.4
peerDependenciesMeta:
'@vitest/browser':
optional: true
- '@vitest/expect@3.0.3':
- resolution: {integrity: sha512-SbRCHU4qr91xguu+dH3RUdI5dC86zm8aZWydbp961aIR7G8OYNN6ZiayFuf9WAngRbFOfdrLHCGgXTj3GtoMRQ==}
-
- '@vitest/mocker@3.0.3':
- resolution: {integrity: sha512-XT2XBc4AN9UdaxJAeIlcSZ0ILi/GzmG5G8XSly4gaiqIvPV3HMTSIDZWJVX6QRJ0PX1m+W8Cy0K9ByXNb/bPIA==}
+ '@vitest/expect@3.2.4':
+ resolution:
+ {
+ integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==,
+ }
+
+ '@vitest/mocker@3.2.4':
+ resolution:
+ {
+ integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==,
+ }
peerDependencies:
msw: ^2.4.9
- vite: ^5.0.0 || ^6.0.0
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
- '@vitest/pretty-format@3.0.3':
- resolution: {integrity: sha512-gCrM9F7STYdsDoNjGgYXKPq4SkSxwwIU5nkaQvdUxiQ0EcNlez+PdKOVIsUJvh9P9IeIFmjn4IIREWblOBpP2Q==}
-
- '@vitest/runner@3.0.3':
- resolution: {integrity: sha512-Rgi2kOAk5ZxWZlwPguRJFOBmWs6uvvyAAR9k3MvjRvYrG7xYvKChZcmnnpJCS98311CBDMqsW9MzzRFsj2gX3g==}
-
- '@vitest/snapshot@3.0.3':
- resolution: {integrity: sha512-kNRcHlI4txBGztuJfPEJ68VezlPAXLRT1u5UCx219TU3kOG2DplNxhWLwDf2h6emwmTPogzLnGVwP6epDaJN6Q==}
-
- '@vitest/spy@3.0.3':
- resolution: {integrity: sha512-7/dgux8ZBbF7lEIKNnEqQlyRaER9nkAL9eTmdKJkDO3hS8p59ATGwKOCUDHcBLKr7h/oi/6hP+7djQk8049T2A==}
-
- '@vitest/utils@3.0.3':
- resolution: {integrity: sha512-f+s8CvyzPtMFY1eZKkIHGhPsQgYo5qCm6O8KZoim9qm1/jT64qBgGpO5tHscNH6BzRHM+edLNOP+3vO8+8pE/A==}
+ '@vitest/pretty-format@3.2.4':
+ resolution:
+ {
+ integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==,
+ }
+
+ '@vitest/runner@3.2.4':
+ resolution:
+ {
+ integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==,
+ }
+
+ '@vitest/snapshot@3.2.4':
+ resolution:
+ {
+ integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==,
+ }
+
+ '@vitest/spy@3.2.4':
+ resolution:
+ {
+ integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==,
+ }
+
+ '@vitest/utils@3.2.4':
+ resolution:
+ {
+ integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==,
+ }
'@yarnpkg/lockfile@1.1.0':
- resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==}
-
- '@yarnpkg/parsers@3.0.0-rc.46':
- resolution: {integrity: sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==}
- engines: {node: '>=14.15.0'}
-
- '@zkochan/js-yaml@0.0.6':
- resolution: {integrity: sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==}
+ resolution:
+ {
+ integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==,
+ }
+
+ '@yarnpkg/parsers@3.0.2':
+ resolution:
+ {
+ integrity: sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==,
+ }
+ engines: { node: '>=18.12.0' }
+
+ '@zkochan/js-yaml@0.0.7':
+ resolution:
+ {
+ integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==,
+ }
hasBin: true
- '@zodios/core@10.9.6':
- resolution: {integrity: sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==}
- peerDependencies:
- axios: ^0.x || ^1.0.0
- zod: ^3.x
-
JSONStream@1.3.5:
- resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
+ resolution:
+ {
+ integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==,
+ }
hasBin: true
- abbrev@1.1.1:
- resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+ abbrev@2.0.0:
+ resolution:
+ {
+ integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
acorn-jsx@5.3.2:
- resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ resolution:
+ {
+ integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==,
+ }
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn-walk@8.3.4:
- resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
- engines: {node: '>=0.4.0'}
-
- acorn@8.14.0:
- resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
- engines: {node: '>=0.4.0'}
+ acorn@8.15.0:
+ resolution:
+ {
+ integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==,
+ }
+ engines: { node: '>=0.4.0' }
hasBin: true
add-stream@1.0.0:
- resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==}
-
- agent-base@6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
-
- agentkeepalive@4.6.0:
- resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
- engines: {node: '>= 8.0.0'}
+ resolution:
+ {
+ integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==,
+ }
+
+ agent-base@7.1.4:
+ resolution:
+ {
+ integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==,
+ }
+ engines: { node: '>= 14' }
aggregate-error@3.1.0:
- resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
- engines: {node: '>=8'}
-
- ajv-draft-04@1.0.0:
- resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
+ resolution:
+ {
+ integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==,
+ }
+ engines: { node: '>=8' }
+
+ ajv-formats@3.0.1:
+ resolution:
+ {
+ integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==,
+ }
peerDependencies:
- ajv: ^8.5.0
+ ajv: ^8.0.0
peerDependenciesMeta:
ajv:
optional: true
ajv@6.12.6:
- resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ resolution:
+ {
+ integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==,
+ }
- ajv@8.17.1:
- resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
+ ajv@8.18.0:
+ resolution:
+ {
+ integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==,
+ }
ansi-colors@4.1.3:
- resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==,
+ }
+ engines: { node: '>=6' }
ansi-escapes@4.3.2:
- resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==,
+ }
+ engines: { node: '>=8' }
ansi-escapes@5.0.0:
- resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==,
+ }
+ engines: { node: '>=12' }
ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
-
- ansi-regex@6.1.0:
- resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
- engines: {node: '>=12'}
-
- ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==,
+ }
+ engines: { node: '>=8' }
+
+ ansi-regex@6.2.2:
+ resolution:
+ {
+ integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==,
+ }
+ engines: { node: '>=12' }
ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==,
+ }
+ engines: { node: '>=8' }
ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
-
- ansi-styles@6.2.1:
- resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
- engines: {node: '>=12'}
-
- any-promise@1.3.0:
- resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
-
- anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
-
- app-module-path@2.2.0:
- resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==}
+ resolution:
+ {
+ integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==,
+ }
+ engines: { node: '>=10' }
+
+ ansi-styles@6.2.3:
+ resolution:
+ {
+ integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==,
+ }
+ engines: { node: '>=12' }
aproba@2.0.0:
- resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
-
- are-we-there-yet@3.0.1:
- resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
- arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+ resolution:
+ {
+ integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==,
+ }
argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ resolution:
+ {
+ integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==,
+ }
argparse@2.0.1:
- resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ resolution:
+ {
+ integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==,
+ }
array-buffer-byte-length@1.0.2:
- resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==,
+ }
+ engines: { node: '>= 0.4' }
array-differ@3.0.0:
- resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==,
+ }
+ engines: { node: '>=8' }
array-ify@1.0.0:
- resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
-
- array-includes@3.1.8:
- resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==,
+ }
+
+ array-includes@3.1.9:
+ resolution:
+ {
+ integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==,
+ }
+ engines: { node: '>= 0.4' }
array-union@2.1.0:
- resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
- engines: {node: '>=8'}
-
- array.prototype.findlastindex@1.2.5:
- resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==,
+ }
+ engines: { node: '>=8' }
+
+ array.prototype.findlastindex@1.2.6:
+ resolution:
+ {
+ integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==,
+ }
+ engines: { node: '>= 0.4' }
array.prototype.flat@1.3.3:
- resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==,
+ }
+ engines: { node: '>= 0.4' }
array.prototype.flatmap@1.3.3:
- resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==,
+ }
+ engines: { node: '>= 0.4' }
arraybuffer.prototype.slice@1.0.4:
- resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==,
+ }
+ engines: { node: '>= 0.4' }
arrify@1.0.1:
- resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==,
+ }
+ engines: { node: '>=0.10.0' }
arrify@2.0.1:
- resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==}
- engines: {node: '>=8'}
-
- assert-plus@1.0.0:
- resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
- engines: {node: '>=0.8'}
+ resolution:
+ {
+ integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==,
+ }
+ engines: { node: '>=8' }
assertion-error@2.0.1:
- resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
- engines: {node: '>=12'}
-
- ast-module-types@5.0.0:
- resolution: {integrity: sha512-JvqziE0Wc0rXQfma0HZC/aY7URXHFuZV84fJRtP8u+lhp0JYCNd5wJzVXP45t0PH0Mej3ynlzvdyITYIu0G4LQ==}
- engines: {node: '>=14'}
-
- astral-regex@2.0.0:
- resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==,
+ }
+ engines: { node: '>=12' }
+
+ ast-v8-to-istanbul@0.3.11:
+ resolution:
+ {
+ integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==,
+ }
+
+ async-function@1.0.0:
+ resolution:
+ {
+ integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==,
+ }
+ engines: { node: '>= 0.4' }
async@3.2.6:
- resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+ resolution:
+ {
+ integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==,
+ }
asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ resolution:
+ {
+ integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==,
+ }
available-typed-arrays@1.0.7:
- resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
- engines: {node: '>= 0.4'}
-
- axios@1.7.9:
- resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
-
- babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.8.0
-
- babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
-
- babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- babel-preset-current-node-syntax@1.1.0:
- resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.0.0
+ resolution:
+ {
+ integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==,
+ }
+ engines: { node: '>= 0.4' }
+
+ axios@1.13.5:
+ resolution:
+ {
+ integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==,
+ }
balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ resolution:
+ {
+ integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==,
+ }
base64-js@1.5.1:
- resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ resolution:
+ {
+ integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==,
+ }
before-after-hook@2.2.3:
- resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
+ resolution:
+ {
+ integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==,
+ }
+
+ bin-links@4.0.4:
+ resolution:
+ {
+ integrity: sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
bl@4.1.0:
- resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
-
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
-
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ resolution:
+ {
+ integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==,
+ }
+
+ brace-expansion@1.1.12:
+ resolution:
+ {
+ integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==,
+ }
+
+ brace-expansion@2.0.2:
+ resolution:
+ {
+ integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==,
+ }
braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
- browserslist@4.24.4:
- resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- bs-logger@0.2.6:
- resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
- engines: {node: '>= 6'}
-
- bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+ resolution:
+ {
+ integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==,
+ }
+ engines: { node: '>=8' }
buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ resolution:
+ {
+ integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==,
+ }
buffer@5.7.1:
- resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
-
- builtins@1.0.3:
- resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==}
-
- builtins@5.1.0:
- resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==}
+ resolution:
+ {
+ integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==,
+ }
byte-size@8.1.1:
- resolution: {integrity: sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==}
- engines: {node: '>=12.17'}
-
- c8@7.14.0:
- resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==}
- engines: {node: '>=10.12.0'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==,
+ }
+ engines: { node: '>=12.17' }
cac@6.7.14:
- resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
- engines: {node: '>=8'}
-
- cacache@16.1.3:
- resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
- cacache@17.1.4:
- resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- cacheable-lookup@7.0.0:
- resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
- engines: {node: '>=14.16'}
-
- cacheable-request@10.2.14:
- resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
- engines: {node: '>=14.16'}
-
- call-bind-apply-helpers@1.0.1:
- resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==,
+ }
+ engines: { node: '>=8' }
+
+ cacache@18.0.4:
+ resolution:
+ {
+ integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ call-bind-apply-helpers@1.0.2:
+ resolution:
+ {
+ integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==,
+ }
+ engines: { node: '>= 0.4' }
call-bind@1.0.8:
- resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
- engines: {node: '>= 0.4'}
-
- call-bound@1.0.3:
- resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==}
- engines: {node: '>= 0.4'}
-
- call-me-maybe@1.0.2:
- resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
+ resolution:
+ {
+ integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==,
+ }
+ engines: { node: '>= 0.4' }
+
+ call-bound@1.0.4:
+ resolution:
+ {
+ integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==,
+ }
+ engines: { node: '>= 0.4' }
callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==,
+ }
+ engines: { node: '>=6' }
camelcase-keys@6.2.2:
- resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==,
+ }
+ engines: { node: '>=8' }
camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
-
- camelcase@6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
-
- caniuse-lite@1.0.30001695:
- resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==}
-
- chai@5.1.2:
- resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==}
- engines: {node: '>=12'}
-
- chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==,
+ }
+ engines: { node: '>=6' }
+
+ chai@5.3.3:
+ resolution:
+ {
+ integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==,
+ }
+ engines: { node: '>=18' }
chalk@4.1.0:
- resolution: {integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==,
+ }
+ engines: { node: '>=10' }
chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==,
+ }
+ engines: { node: '>=10' }
chalk@5.3.0:
- resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-
- chalk@5.4.1:
- resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-
- change-case@5.4.4:
- resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
-
- char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
-
- chardet@0.7.0:
- resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
-
- check-error@2.1.1:
- resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
- engines: {node: '>= 16'}
+ resolution:
+ {
+ integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==,
+ }
+ engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
+
+ chalk@5.6.2:
+ resolution:
+ {
+ integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==,
+ }
+ engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
+
+ chardet@2.1.1:
+ resolution:
+ {
+ integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==,
+ }
+
+ check-error@2.1.3:
+ resolution:
+ {
+ integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==,
+ }
+ engines: { node: '>= 16' }
chownr@2.0.0:
- resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==,
+ }
+ engines: { node: '>=10' }
ci-info@3.9.0:
- resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
- engines: {node: '>=8'}
-
- cjs-module-lexer@1.4.1:
- resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==}
+ resolution:
+ {
+ integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==,
+ }
+ engines: { node: '>=8' }
+
+ ci-info@4.4.0:
+ resolution:
+ {
+ integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==,
+ }
+ engines: { node: '>=8' }
clean-stack@2.2.0:
- resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==,
+ }
+ engines: { node: '>=6' }
cli-cursor@3.1.0:
- resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==,
+ }
+ engines: { node: '>=8' }
cli-cursor@4.0.0:
- resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
cli-cursor@5.0.0:
- resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==,
+ }
+ engines: { node: '>=18' }
cli-spinners@2.6.1:
- resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==,
+ }
+ engines: { node: '>=6' }
cli-spinners@2.9.2:
- resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==,
+ }
+ engines: { node: '>=6' }
cli-truncate@3.1.0:
- resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
cli-width@3.0.0:
- resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
- engines: {node: '>= 10'}
+ resolution:
+ {
+ integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==,
+ }
+ engines: { node: '>= 10' }
cli-width@4.1.0:
- resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
- engines: {node: '>= 12'}
+ resolution:
+ {
+ integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==,
+ }
+ engines: { node: '>= 12' }
cliui@7.0.4:
- resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+ resolution:
+ {
+ integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==,
+ }
cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==,
+ }
+ engines: { node: '>=12' }
clone-deep@4.0.1:
- resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==,
+ }
+ engines: { node: '>=6' }
clone@1.0.4:
- resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
- engines: {node: '>=0.8'}
-
- cmd-shim@6.0.1:
- resolution: {integrity: sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
-
- code-error-fragment@0.0.230:
- resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==}
- engines: {node: '>= 4'}
-
- collect-v8-coverage@1.0.2:
- resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
-
- color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ resolution:
+ {
+ integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==,
+ }
+ engines: { node: '>=0.8' }
+
+ cmd-shim@6.0.3:
+ resolution:
+ {
+ integrity: sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
-
- color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+ resolution:
+ {
+ integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==,
+ }
+ engines: { node: '>=7.0.0' }
color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ resolution:
+ {
+ integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==,
+ }
color-support@1.1.3:
- resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
+ resolution:
+ {
+ integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==,
+ }
hasBin: true
+ colorette@1.4.0:
+ resolution:
+ {
+ integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==,
+ }
+
colorette@2.0.20:
- resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+ resolution:
+ {
+ integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==,
+ }
columnify@1.6.0:
- resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ {
+ integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==,
+ }
+ engines: { node: '>=8.0.0' }
combined-stream@1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
-
- commander@10.0.1:
- resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==,
+ }
+ engines: { node: '>= 0.8' }
commander@11.0.0:
- resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==}
- engines: {node: '>=16'}
+ resolution:
+ {
+ integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==,
+ }
+ engines: { node: '>=16' }
commander@12.1.0:
- resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
- engines: {node: '>=18'}
-
- commander@7.2.0:
- resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
- engines: {node: '>= 10'}
-
- commander@8.3.0:
- resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
- engines: {node: '>= 12'}
-
- commander@9.5.0:
- resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
- engines: {node: ^12.20.0 || >=14}
-
- commondir@1.0.1:
- resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
+ resolution:
+ {
+ integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==,
+ }
+ engines: { node: '>=18' }
+
+ common-ancestor-path@1.0.1:
+ resolution:
+ {
+ integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==,
+ }
compare-func@2.0.0:
- resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
+ resolution:
+ {
+ integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==,
+ }
concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ resolution:
+ {
+ integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==,
+ }
concat-stream@2.0.0:
- resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
- engines: {'0': node >= 6.0}
-
- config-chain@1.1.13:
- resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+ resolution:
+ {
+ integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==,
+ }
+ engines: { '0': node >= 6.0 }
console-control-strings@1.1.0:
- resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
+ resolution:
+ {
+ integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==,
+ }
conventional-changelog-angular@7.0.0:
- resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==}
- engines: {node: '>=16'}
+ resolution:
+ {
+ integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==,
+ }
+ engines: { node: '>=16' }
conventional-changelog-core@5.0.1:
- resolution: {integrity: sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==,
+ }
+ engines: { node: '>=14' }
conventional-changelog-preset-loader@3.0.0:
- resolution: {integrity: sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==,
+ }
+ engines: { node: '>=14' }
conventional-changelog-writer@6.0.1:
- resolution: {integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==,
+ }
+ engines: { node: '>=14' }
hasBin: true
conventional-commits-filter@3.0.0:
- resolution: {integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==,
+ }
+ engines: { node: '>=14' }
conventional-commits-parser@4.0.0:
- resolution: {integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==,
+ }
+ engines: { node: '>=14' }
hasBin: true
conventional-recommended-bump@7.0.1:
- resolution: {integrity: sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==,
+ }
+ engines: { node: '>=14' }
hasBin: true
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
- convict@6.2.4:
- resolution: {integrity: sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==}
- engines: {node: '>=6'}
-
core-util-is@1.0.2:
- resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
-
- core-util-is@1.0.3:
- resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
-
- cosmiconfig@8.3.6:
- resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==,
+ }
+
+ cosmiconfig@9.0.0:
+ resolution:
+ {
+ integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==,
+ }
+ engines: { node: '>=14' }
peerDependencies:
typescript: '>=4.9.5'
peerDependenciesMeta:
typescript:
optional: true
- create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
-
- create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
-
- cross-spawn@5.1.0:
- resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
-
cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==,
+ }
+ engines: { node: '>= 8' }
+
+ cssesc@3.0.0:
+ resolution:
+ {
+ integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==,
+ }
+ engines: { node: '>=4' }
+ hasBin: true
dargs@7.0.0:
- resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==,
+ }
+ engines: { node: '>=8' }
data-view-buffer@1.0.2:
- resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==,
+ }
+ engines: { node: '>= 0.4' }
data-view-byte-length@1.0.2:
- resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==,
+ }
+ engines: { node: '>= 0.4' }
data-view-byte-offset@1.0.1:
- resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==,
+ }
+ engines: { node: '>= 0.4' }
dateformat@3.0.3:
- resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
+ resolution:
+ {
+ integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==,
+ }
debug@3.2.7:
- resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ resolution:
+ {
+ integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==,
+ }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -2112,17 +2608,23 @@ packages:
optional: true
debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
+ resolution:
+ {
+ integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==,
+ }
+ engines: { node: '>=6.0' }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
- debug@4.4.0:
- resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
- engines: {node: '>=6.0'}
+ debug@4.4.3:
+ resolution:
+ {
+ integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==,
+ }
+ engines: { node: '>=6.0' }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -2130,22 +2632,24 @@ packages:
optional: true
decamelize-keys@1.1.1:
- resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==,
+ }
+ engines: { node: '>=0.10.0' }
decamelize@1.2.0:
- resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
- engines: {node: '>=0.10.0'}
-
- decompress-response@6.0.0:
- resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
- engines: {node: '>=10'}
-
- dedent@0.7.0:
- resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
+ resolution:
+ {
+ integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==,
+ }
+ engines: { node: '>=0.10.0' }
dedent@1.5.3:
- resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==}
+ resolution:
+ {
+ integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==,
+ }
peerDependencies:
babel-plugin-macros: ^3.1.0
peerDependenciesMeta:
@@ -2153,259 +2657,304 @@ packages:
optional: true
deep-eql@5.0.2:
- resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
- engines: {node: '>=6'}
-
- deep-extend@0.6.0:
- resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
- engines: {node: '>=4.0.0'}
+ resolution:
+ {
+ integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==,
+ }
+ engines: { node: '>=6' }
deep-is@0.1.4:
- resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
-
- deepmerge@4.3.1:
- resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==,
+ }
defaults@1.0.4:
- resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
-
- defer-to-connect@2.0.1:
- resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==,
+ }
define-data-property@1.1.4:
- resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==,
+ }
+ engines: { node: '>= 0.4' }
define-lazy-prop@2.0.0:
- resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==,
+ }
+ engines: { node: '>=8' }
define-properties@1.2.1:
- resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==,
+ }
+ engines: { node: '>= 0.4' }
delayed-stream@1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
-
- delegates@1.0.0:
- resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
-
- dependency-tree@10.0.9:
- resolution: {integrity: sha512-dwc59FRIsht+HfnTVM0BCjJaEWxdq2YAvEDy4/Hn6CwS3CBWMtFnL3aZGAkQn3XCYxk/YcTDE4jX2Q7bFTwCjA==}
- engines: {node: '>=14'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==,
+ }
+ engines: { node: '>=0.4.0' }
deprecation@2.3.1:
- resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
+ resolution:
+ {
+ integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==,
+ }
detect-indent@5.0.0:
- resolution: {integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==}
- engines: {node: '>=4'}
-
- detect-indent@6.1.0:
- resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
- engines: {node: '>=8'}
-
- detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
-
- detective-amd@5.0.2:
- resolution: {integrity: sha512-XFd/VEQ76HSpym80zxM68ieB77unNuoMwopU2TFT/ErUk5n4KvUTwW4beafAVUugrjV48l4BmmR0rh2MglBaiA==}
- engines: {node: '>=14'}
- hasBin: true
-
- detective-cjs@5.0.1:
- resolution: {integrity: sha512-6nTvAZtpomyz/2pmEmGX1sXNjaqgMplhQkskq2MLrar0ZAIkHMrDhLXkRiK2mvbu9wSWr0V5/IfiTrZqAQMrmQ==}
- engines: {node: '>=14'}
-
- detective-es6@4.0.1:
- resolution: {integrity: sha512-k3Z5tB4LQ8UVHkuMrFOlvb3GgFWdJ9NqAa2YLUU/jTaWJIm+JJnEh4PsMc+6dfT223Y8ACKOaC0qcj7diIhBKw==}
- engines: {node: '>=14'}
-
- detective-postcss@6.1.3:
- resolution: {integrity: sha512-7BRVvE5pPEvk2ukUWNQ+H2XOq43xENWbH0LcdCE14mwgTBEAMoAx+Fc1rdp76SmyZ4Sp48HlV7VedUnP6GA1Tw==}
- engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-
- detective-sass@5.0.3:
- resolution: {integrity: sha512-YsYT2WuA8YIafp2RVF5CEfGhhyIVdPzlwQgxSjK+TUm3JoHP+Tcorbk3SfG0cNZ7D7+cYWa0ZBcvOaR0O8+LlA==}
- engines: {node: '>=14'}
-
- detective-scss@4.0.3:
- resolution: {integrity: sha512-VYI6cHcD0fLokwqqPFFtDQhhSnlFWvU614J42eY6G0s8c+MBhi9QAWycLwIOGxlmD8I/XvGSOUV1kIDhJ70ZPg==}
- engines: {node: '>=14'}
-
- detective-stylus@4.0.0:
- resolution: {integrity: sha512-TfPotjhszKLgFBzBhTOxNHDsutIxx9GTWjrL5Wh7Qx/ydxKhwUrlSFeLIn+ZaHPF+h0siVBkAQSuy6CADyTxgQ==}
- engines: {node: '>=14'}
-
- detective-typescript@11.2.0:
- resolution: {integrity: sha512-ARFxjzizOhPqs1fYC/2NMC3N4jrQ6HvVflnXBTRqNEqJuXwyKLRr9CrJwkRcV/SnZt1sNXgsF6FPm0x57Tq0rw==}
- engines: {node: ^14.14.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==,
+ }
+ engines: { node: '>=4' }
diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
+ resolution:
+ {
+ integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==,
+ }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
dir-glob@3.0.1:
- resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==,
+ }
+ engines: { node: '>=8' }
doctrine@2.1.0:
- resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==,
+ }
+ engines: { node: '>=0.10.0' }
doctrine@3.0.0:
- resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ {
+ integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==,
+ }
+ engines: { node: '>=6.0.0' }
dot-prop@5.3.0:
- resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
- engines: {node: '>=8'}
-
- dotenv-expand@10.0.0:
- resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
- engines: {node: '>=12'}
-
- dotenv@16.3.2:
- resolution: {integrity: sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==,
+ }
+ engines: { node: '>=8' }
+
+ dotenv-expand@11.0.7:
+ resolution:
+ {
+ integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==,
+ }
+ engines: { node: '>=12' }
+
+ dotenv@16.4.7:
+ resolution:
+ {
+ integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==,
+ }
+ engines: { node: '>=12' }
dunder-proto@1.0.1:
- resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
- engines: {node: '>= 0.4'}
-
- duplexer@0.1.2:
- resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+ resolution:
+ {
+ integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==,
+ }
+ engines: { node: '>= 0.4' }
eastasianwidth@0.2.0:
- resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+ resolution:
+ {
+ integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==,
+ }
ejs@3.1.10:
- resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==,
+ }
+ engines: { node: '>=0.10.0' }
hasBin: true
- electron-to-chromium@1.5.83:
- resolution: {integrity: sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==}
-
- emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
-
- emoji-regex@10.4.0:
- resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
+ emoji-regex@10.6.0:
+ resolution:
+ {
+ integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==,
+ }
emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ resolution:
+ {
+ integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==,
+ }
emoji-regex@9.2.2:
- resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ resolution:
+ {
+ integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==,
+ }
encoding@0.1.13:
- resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
+ resolution:
+ {
+ integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==,
+ }
- end-of-stream@1.4.4:
- resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
-
- enhanced-resolve@5.18.0:
- resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==}
- engines: {node: '>=10.13.0'}
+ end-of-stream@1.4.5:
+ resolution:
+ {
+ integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==,
+ }
enquirer@2.3.6:
- resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
- engines: {node: '>=8.6'}
+ resolution:
+ {
+ integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==,
+ }
+ engines: { node: '>=8.6' }
env-paths@2.2.1:
- resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
- engines: {node: '>=6'}
-
- envinfo@7.8.1:
- resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==,
+ }
+ engines: { node: '>=6' }
+
+ envinfo@7.13.0:
+ resolution:
+ {
+ integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==,
+ }
+ engines: { node: '>=4' }
hasBin: true
err-code@2.0.3:
- resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
-
- error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
-
- es-abstract@1.23.9:
- resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==,
+ }
+
+ error-ex@1.3.4:
+ resolution:
+ {
+ integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==,
+ }
+
+ es-abstract@1.24.1:
+ resolution:
+ {
+ integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==,
+ }
+ engines: { node: '>= 0.4' }
es-define-property@1.0.1:
- resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==,
+ }
+ engines: { node: '>= 0.4' }
es-errors@1.3.0:
- resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
- engines: {node: '>= 0.4'}
-
- es-module-lexer@1.6.0:
- resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+ resolution:
+ {
+ integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==,
+ }
+ engines: { node: '>= 0.4' }
+
+ es-module-lexer@1.7.0:
+ resolution:
+ {
+ integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==,
+ }
es-object-atoms@1.1.1:
- resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==,
+ }
+ engines: { node: '>= 0.4' }
es-set-tostringtag@2.1.0:
- resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
- engines: {node: '>= 0.4'}
-
- es-shim-unscopables@1.0.2:
- resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
+ resolution:
+ {
+ integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==,
+ }
+ engines: { node: '>= 0.4' }
+
+ es-shim-unscopables@1.1.0:
+ resolution:
+ {
+ integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==,
+ }
+ engines: { node: '>= 0.4' }
es-to-primitive@1.3.0:
- resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
- engines: {node: '>= 0.4'}
-
- esbuild@0.24.2:
- resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==,
+ }
+ engines: { node: '>= 0.4' }
+
+ esbuild@0.27.3:
+ resolution:
+ {
+ integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==,
+ }
+ engines: { node: '>=18' }
hasBin: true
escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==,
+ }
+ engines: { node: '>=6' }
escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
-
- escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==,
+ }
+ engines: { node: '>=0.8.0' }
escape-string-regexp@4.0.0:
- resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
- engines: {node: '>=10'}
-
- escodegen@2.1.0:
- resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
- engines: {node: '>=6.0'}
- hasBin: true
-
- eslint-config-prettier@9.1.0:
- resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
+ resolution:
+ {
+ integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==,
+ }
+ engines: { node: '>=10' }
+
+ eslint-config-prettier@9.1.2:
+ resolution:
+ {
+ integrity: sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==,
+ }
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
eslint-import-resolver-node@0.3.9:
- resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
-
- eslint-import-resolver-typescript@3.7.0:
- resolution: {integrity: sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==,
+ }
+
+ eslint-import-resolver-typescript@3.10.1:
+ resolution:
+ {
+ integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==,
+ }
+ engines: { node: ^14.18.0 || >=16.0.0 }
peerDependencies:
eslint: '*'
eslint-plugin-import: '*'
@@ -2416,9 +2965,12 @@ packages:
eslint-plugin-import-x:
optional: true
- eslint-module-utils@2.12.0:
- resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
- engines: {node: '>=4'}
+ eslint-module-utils@2.12.1:
+ resolution:
+ {
+ integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==,
+ }
+ engines: { node: '>=4' }
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
@@ -2437,9 +2989,12 @@ packages:
eslint-import-resolver-webpack:
optional: true
- eslint-plugin-import@2.31.0:
- resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
- engines: {node: '>=4'}
+ eslint-plugin-import@2.32.0:
+ resolution:
+ {
+ integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==,
+ }
+ engines: { node: '>=4' }
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
@@ -2447,13 +3002,16 @@ packages:
'@typescript-eslint/parser':
optional: true
- eslint-plugin-prettier@5.2.3:
- resolution: {integrity: sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ eslint-plugin-prettier@5.5.5:
+ resolution:
+ {
+ integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==,
+ }
+ engines: { node: ^14.18.0 || >=16.0.0 }
peerDependencies:
'@types/eslint': '>=8.0.0'
eslint: '>=8.0.0'
- eslint-config-prettier: '*'
+ eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0'
prettier: '>=3.0.0'
peerDependenciesMeta:
'@types/eslint':
@@ -2462,1086 +3020,1418 @@ packages:
optional: true
eslint-scope@7.2.2:
- resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
eslint-visitor-keys@3.4.3:
- resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
eslint@8.57.1:
- resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
+ resolution:
+ {
+ integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
hasBin: true
espree@9.6.1:
- resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==,
+ }
+ engines: { node: '>=4' }
hasBin: true
- esquery@1.6.0:
- resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
- engines: {node: '>=0.10'}
+ esquery@1.7.0:
+ resolution:
+ {
+ integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==,
+ }
+ engines: { node: '>=0.10' }
esrecurse@4.3.0:
- resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
- engines: {node: '>=4.0'}
+ resolution:
+ {
+ integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==,
+ }
+ engines: { node: '>=4.0' }
estraverse@5.3.0:
- resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
- engines: {node: '>=4.0'}
+ resolution:
+ {
+ integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==,
+ }
+ engines: { node: '>=4.0' }
estree-walker@3.0.3:
- resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ resolution:
+ {
+ integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==,
+ }
esutils@2.0.3:
- resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
- engines: {node: '>=0.10.0'}
-
- eval-estree-expression@2.0.3:
- resolution: {integrity: sha512-6zXgUV+NHvx6PwHxPsIQ8T4cCUgsnhaH6ZyYF1OSKZIrkcAzvSvZgHAbdj72GlNm8eH6c8FI8ywcwqm42Xq1aQ==}
+ resolution:
+ {
+ integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==,
+ }
+ engines: { node: '>=0.10.0' }
eventemitter3@4.0.7:
- resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ resolution:
+ {
+ integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==,
+ }
- eventemitter3@5.0.1:
- resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ eventemitter3@5.0.4:
+ resolution:
+ {
+ integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==,
+ }
execa@5.0.0:
- resolution: {integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==}
- engines: {node: '>=10'}
-
- execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==,
+ }
+ engines: { node: '>=10' }
execa@7.2.0:
- resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
- engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
-
- exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
-
- expect-type@1.1.0:
- resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
- engines: {node: '>=12.0.0'}
-
- expect@29.7.0:
- resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- exponential-backoff@3.1.1:
- resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
-
- external-editor@3.1.0:
- resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
- engines: {node: '>=4'}
-
- extsprintf@1.4.1:
- resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==}
- engines: {'0': node >=0.6.0}
+ resolution:
+ {
+ integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==,
+ }
+ engines: { node: ^14.18.0 || ^16.14.0 || >=18.0.0 }
+
+ expect-type@1.3.0:
+ resolution:
+ {
+ integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==,
+ }
+ engines: { node: '>=12.0.0' }
+
+ exponential-backoff@3.1.3:
+ resolution:
+ {
+ integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==,
+ }
fast-deep-equal@3.1.3:
- resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ resolution:
+ {
+ integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
+ }
fast-diff@1.3.0:
- resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+ resolution:
+ {
+ integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==,
+ }
fast-glob@3.3.3:
- resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
- engines: {node: '>=8.6.0'}
+ resolution:
+ {
+ integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==,
+ }
+ engines: { node: '>=8.6.0' }
fast-json-stable-stringify@2.1.0:
- resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ resolution:
+ {
+ integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==,
+ }
fast-levenshtein@2.0.6:
- resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
-
- fast-uri@3.0.6:
- resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
-
- fastq@1.18.0:
- resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==}
-
- fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+ resolution:
+ {
+ integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==,
+ }
+
+ fast-uri@3.1.0:
+ resolution:
+ {
+ integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==,
+ }
+
+ fastq@1.20.1:
+ resolution:
+ {
+ integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==,
+ }
+
+ fdir@6.5.0:
+ resolution:
+ {
+ integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==,
+ }
+ engines: { node: '>=12.0.0' }
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
figures@3.2.0:
- resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==,
+ }
+ engines: { node: '>=8' }
file-entry-cache@6.0.1:
- resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ resolution:
+ {
+ integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==,
+ }
+ engines: { node: ^10.12.0 || >=12.0.0 }
filelist@1.0.4:
- resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
-
- filing-cabinet@4.2.0:
- resolution: {integrity: sha512-YZ21ryzRcyqxpyKggdYSoXx//d3sCJzM3lsYoaeg/FyXdADGJrUl+BW1KIglaVLJN5BBcMtWylkygY8zBp2MrQ==}
- engines: {node: '>=14'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==,
+ }
fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==,
+ }
+ engines: { node: '>=8' }
find-up@2.1.0:
- resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==,
+ }
+ engines: { node: '>=4' }
find-up@4.1.0:
- resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==,
+ }
+ engines: { node: '>=8' }
find-up@5.0.0:
- resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==,
+ }
+ engines: { node: '>=10' }
flat-cache@3.2.0:
- resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ resolution:
+ {
+ integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==,
+ }
+ engines: { node: ^10.12.0 || >=12.0.0 }
flat@5.0.2:
- resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
+ resolution:
+ {
+ integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==,
+ }
hasBin: true
- flatted@3.3.2:
- resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
-
- follow-redirects@1.15.6:
- resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
- engines: {node: '>=4.0'}
+ flatted@3.3.3:
+ resolution:
+ {
+ integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==,
+ }
+
+ follow-redirects@1.15.11:
+ resolution:
+ {
+ integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==,
+ }
+ engines: { node: '>=4.0' }
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
- for-each@0.3.3:
- resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
-
- foreground-child@2.0.0:
- resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
- engines: {node: '>=8.0.0'}
-
- foreground-child@3.3.0:
- resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
- engines: {node: '>=14'}
-
- form-data-encoder@2.1.4:
- resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
- engines: {node: '>= 14.17'}
-
- form-data@4.0.1:
- resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
- engines: {node: '>= 6'}
+ for-each@0.3.5:
+ resolution:
+ {
+ integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==,
+ }
+ engines: { node: '>= 0.4' }
+
+ foreground-child@3.3.1:
+ resolution:
+ {
+ integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==,
+ }
+ engines: { node: '>=14' }
+
+ form-data@4.0.5:
+ resolution:
+ {
+ integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==,
+ }
+ engines: { node: '>= 6' }
+
+ front-matter@4.0.2:
+ resolution:
+ {
+ integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==,
+ }
fs-constants@1.0.0:
- resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
-
- fs-extra@10.1.0:
- resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
- engines: {node: '>=12'}
-
- fs-extra@11.3.0:
- resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
- engines: {node: '>=14.14'}
-
- fs-extra@8.1.0:
- resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
- engines: {node: '>=6 <7 || >=8'}
+ resolution:
+ {
+ integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==,
+ }
+
+ fs-extra@11.3.3:
+ resolution:
+ {
+ integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==,
+ }
+ engines: { node: '>=14.14' }
fs-minipass@2.1.0:
- resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==,
+ }
+ engines: { node: '>= 8' }
fs-minipass@3.0.3:
- resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ resolution:
+ {
+ integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==,
+ }
fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ resolution:
+ {
+ integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==,
+ }
+ engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
os: [darwin]
function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ resolution:
+ {
+ integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==,
+ }
function.prototype.name@1.1.8:
- resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==,
+ }
+ engines: { node: '>= 0.4' }
functions-have-names@1.2.3:
- resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
-
- gauge@4.0.4:
- resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
-
- get-amd-module-type@5.0.1:
- resolution: {integrity: sha512-jb65zDeHyDjFR1loOVk0HQGM5WNwoGB8aLWy3LKCieMKol0/ProHkhO2X1JxojuN10vbz1qNn09MJ7tNp7qMzw==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==,
+ }
+
+ generator-function@2.0.1:
+ resolution:
+ {
+ integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==,
+ }
+ engines: { node: '>= 0.4' }
get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
-
- get-east-asian-width@1.3.0:
- resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
- engines: {node: '>=18'}
-
- get-intrinsic@1.2.7:
- resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
- engines: {node: '>= 0.4'}
-
- get-own-enumerable-property-symbols@3.0.2:
- resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
-
- get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ {
+ integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==,
+ }
+ engines: { node: 6.* || 8.* || >= 10.* }
+
+ get-east-asian-width@1.4.0:
+ resolution:
+ {
+ integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==,
+ }
+ engines: { node: '>=18' }
+
+ get-intrinsic@1.3.0:
+ resolution:
+ {
+ integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==,
+ }
+ engines: { node: '>= 0.4' }
get-pkg-repo@4.2.1:
- resolution: {integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ {
+ integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==,
+ }
+ engines: { node: '>=6.9.0' }
hasBin: true
get-port@5.1.1:
- resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==,
+ }
+ engines: { node: '>=8' }
get-proto@1.0.1:
- resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==,
+ }
+ engines: { node: '>= 0.4' }
get-stream@6.0.0:
- resolution: {integrity: sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==,
+ }
+ engines: { node: '>=10' }
get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==,
+ }
+ engines: { node: '>=10' }
get-symbol-description@1.1.0:
- resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
- engines: {node: '>= 0.4'}
-
- get-tsconfig@4.9.0:
- resolution: {integrity: sha512-52n24W52sIueosRe0XZ8Ex5Yle+WbhfCKnV/gWXpbVR8FXNTfqdKEKUSypKso66VRHTvvcQxL44UTZbJRlCTnw==}
+ resolution:
+ {
+ integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==,
+ }
+ engines: { node: '>= 0.4' }
+
+ get-tsconfig@4.13.6:
+ resolution:
+ {
+ integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==,
+ }
git-raw-commits@3.0.0:
- resolution: {integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==,
+ }
+ engines: { node: '>=14' }
hasBin: true
git-remote-origin-url@2.0.0:
- resolution: {integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==,
+ }
+ engines: { node: '>=4' }
git-semver-tags@5.0.1:
- resolution: {integrity: sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==,
+ }
+ engines: { node: '>=14' }
hasBin: true
git-up@7.0.0:
- resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==}
+ resolution:
+ {
+ integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==,
+ }
- git-url-parse@13.1.0:
- resolution: {integrity: sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==}
+ git-url-parse@14.0.0:
+ resolution:
+ {
+ integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==,
+ }
gitconfiglocal@1.0.0:
- resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==}
+ resolution:
+ {
+ integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==,
+ }
glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==,
+ }
+ engines: { node: '>= 6' }
glob-parent@6.0.2:
- resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
- engines: {node: '>=10.13.0'}
-
- glob@10.4.5:
- resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ resolution:
+ {
+ integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==,
+ }
+ engines: { node: '>=10.13.0' }
+
+ glob@10.5.0:
+ resolution:
+ {
+ integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==,
+ }
hasBin: true
- glob@7.1.4:
- resolution: {integrity: sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==}
- deprecated: Glob versions prior to v9 are no longer supported
-
glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Glob versions prior to v9 are no longer supported
-
- glob@8.1.0:
- resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
- engines: {node: '>=12'}
- deprecated: Glob versions prior to v9 are no longer supported
+ resolution:
+ {
+ integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==,
+ }
glob@9.3.5:
- resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
- engines: {node: '>=16 || 14 >=14.17'}
-
- globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
globals@13.24.0:
- resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==,
+ }
+ engines: { node: '>=8' }
globalthis@1.0.4:
- resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==,
+ }
+ engines: { node: '>= 0.4' }
globby@11.1.0:
- resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
- engines: {node: '>=10'}
-
- globby@14.0.2:
- resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==}
- engines: {node: '>=18'}
-
- gonzales-pe@4.3.0:
- resolution: {integrity: sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==}
- engines: {node: '>=0.6.0'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==,
+ }
+ engines: { node: '>=10' }
gopd@1.2.0:
- resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
- engines: {node: '>= 0.4'}
-
- got@12.6.1:
- resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==}
- engines: {node: '>=14.16'}
-
- graceful-fs@4.2.10:
- resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
+ resolution:
+ {
+ integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==,
+ }
+ engines: { node: '>= 0.4' }
graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- grapheme-splitter@1.0.4:
- resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+ resolution:
+ {
+ integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==,
+ }
graphemer@1.4.0:
- resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ resolution:
+ {
+ integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==,
+ }
handlebars@4.7.8:
- resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
- engines: {node: '>=0.4.7'}
+ resolution:
+ {
+ integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==,
+ }
+ engines: { node: '>=0.4.7' }
hasBin: true
hard-rejection@2.1.0:
- resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==,
+ }
+ engines: { node: '>=6' }
has-bigints@1.1.0:
- resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
- engines: {node: '>= 0.4'}
-
- has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==,
+ }
+ engines: { node: '>= 0.4' }
has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==,
+ }
+ engines: { node: '>=8' }
has-property-descriptors@1.0.2:
- resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+ resolution:
+ {
+ integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==,
+ }
has-proto@1.2.0:
- resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==,
+ }
+ engines: { node: '>= 0.4' }
has-symbols@1.1.0:
- resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==,
+ }
+ engines: { node: '>= 0.4' }
has-tostringtag@1.0.2:
- resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==,
+ }
+ engines: { node: '>= 0.4' }
has-unicode@2.0.1:
- resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
+ resolution:
+ {
+ integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==,
+ }
hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==,
+ }
+ engines: { node: '>= 0.4' }
hosted-git-info@2.8.9:
- resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
-
- hosted-git-info@3.0.8:
- resolution: {integrity: sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==,
+ }
hosted-git-info@4.1.0:
- resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
- engines: {node: '>=10'}
-
- hosted-git-info@6.1.3:
- resolution: {integrity: sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==,
+ }
+ engines: { node: '>=10' }
+
+ hosted-git-info@7.0.2:
+ resolution:
+ {
+ integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-
- http-cache-semantics@4.1.1:
- resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
-
- http-proxy-agent@5.0.0:
- resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
- engines: {node: '>= 6'}
-
- http2-wrapper@2.2.1:
- resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
- engines: {node: '>=10.19.0'}
-
- https-proxy-agent@5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==,
+ }
+
+ http-cache-semantics@4.2.0:
+ resolution:
+ {
+ integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==,
+ }
+
+ http-proxy-agent@7.0.2:
+ resolution:
+ {
+ integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==,
+ }
+ engines: { node: '>= 14' }
+
+ https-proxy-agent@7.0.6:
+ resolution:
+ {
+ integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==,
+ }
+ engines: { node: '>= 14' }
human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
+ resolution:
+ {
+ integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==,
+ }
+ engines: { node: '>=10.17.0' }
human-signals@4.3.1:
- resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
- engines: {node: '>=14.18.0'}
-
- humanize-ms@1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
+ resolution:
+ {
+ integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==,
+ }
+ engines: { node: '>=14.18.0' }
husky@8.0.3:
- resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==,
+ }
+ engines: { node: '>=14' }
hasBin: true
- iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
-
iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==,
+ }
+ engines: { node: '>=0.10.0' }
+
+ iconv-lite@0.7.2:
+ resolution:
+ {
+ integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==,
+ }
+ engines: { node: '>=0.10.0' }
ieee754@1.2.1:
- resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
-
- ignore-walk@5.0.1:
- resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==,
+ }
ignore-walk@6.0.5:
- resolution: {integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
ignore@5.3.2:
- resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
- engines: {node: '>= 4'}
-
- import-fresh@3.3.0:
- resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==,
+ }
+ engines: { node: '>= 4' }
+
+ import-fresh@3.3.1:
+ resolution:
+ {
+ integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==,
+ }
+ engines: { node: '>=6' }
import-local@3.1.0:
- resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
- engines: {node: '>=8'}
- hasBin: true
-
- import-local@3.2.0:
- resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==,
+ }
+ engines: { node: '>=8' }
hasBin: true
imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
+ resolution:
+ {
+ integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==,
+ }
+ engines: { node: '>=0.8.19' }
indent-string@4.0.0:
- resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
- engines: {node: '>=8'}
-
- infer-owner@1.0.4:
- resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
+ resolution:
+ {
+ integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==,
+ }
+ engines: { node: '>=8' }
inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+ resolution:
+ {
+ integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==,
+ }
inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ resolution:
+ {
+ integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==,
+ }
ini@1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
-
- init-package-json@5.0.0:
- resolution: {integrity: sha512-kBhlSheBfYmq3e0L1ii+VKe3zBTLL5lDCDWR+f9dLmEGSB3MqLlMlsolubSsyI88Bg6EA+BIMlomAnQ1SwgQBw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- inquirer@12.3.2:
- resolution: {integrity: sha512-YjQCIcDd3yyDuQrbII0FBtm/ZqNoWtvaC71yeCnd5Vbg4EgzsAGaemzfpzmqfvIZEp2roSwuZZKdM0C65hA43g==}
- engines: {node: '>=18'}
- peerDependencies:
- '@types/node': '>=18'
-
- inquirer@8.2.6:
- resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ {
+ integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==,
+ }
+
+ ini@4.1.3:
+ resolution:
+ {
+ integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ init-package-json@6.0.3:
+ resolution:
+ {
+ integrity: sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ inquirer@8.2.7:
+ resolution:
+ {
+ integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==,
+ }
+ engines: { node: '>=12.0.0' }
internal-slot@1.1.0:
- resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
- engines: {node: '>= 0.4'}
-
- ip-address@9.0.5:
- resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
- engines: {node: '>= 12'}
-
- ip@2.0.1:
- resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==}
+ resolution:
+ {
+ integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==,
+ }
+ engines: { node: '>= 0.4' }
+
+ ip-address@10.1.0:
+ resolution:
+ {
+ integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==,
+ }
+ engines: { node: '>= 12' }
is-array-buffer@3.0.5:
- resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==,
+ }
+ engines: { node: '>= 0.4' }
is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
-
- is-async-function@2.1.0:
- resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==,
+ }
+
+ is-async-function@2.1.1:
+ resolution:
+ {
+ integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==,
+ }
+ engines: { node: '>= 0.4' }
is-bigint@1.1.0:
- resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
- engines: {node: '>= 0.4'}
-
- is-boolean-object@1.2.1:
- resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==}
- engines: {node: '>= 0.4'}
-
- is-bun-module@1.3.0:
- resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==}
+ resolution:
+ {
+ integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==,
+ }
+ engines: { node: '>= 0.4' }
+
+ is-boolean-object@1.2.2:
+ resolution:
+ {
+ integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==,
+ }
+ engines: { node: '>= 0.4' }
+
+ is-bun-module@2.0.0:
+ resolution:
+ {
+ integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==,
+ }
is-callable@1.2.7:
- resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==,
+ }
+ engines: { node: '>= 0.4' }
is-ci@3.0.1:
- resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
+ resolution:
+ {
+ integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==,
+ }
hasBin: true
is-core-module@2.16.1:
- resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==,
+ }
+ engines: { node: '>= 0.4' }
is-data-view@1.0.2:
- resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==,
+ }
+ engines: { node: '>= 0.4' }
is-date-object@1.1.0:
- resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==,
+ }
+ engines: { node: '>= 0.4' }
is-docker@2.2.1:
- resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==,
+ }
+ engines: { node: '>=8' }
hasBin: true
is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==,
+ }
+ engines: { node: '>=0.10.0' }
is-finalizationregistry@1.1.1:
- resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==,
+ }
+ engines: { node: '>= 0.4' }
is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==,
+ }
+ engines: { node: '>=8' }
is-fullwidth-code-point@4.0.0:
- resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
- engines: {node: '>=12'}
-
- is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
-
- is-generator-function@1.1.0:
- resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==,
+ }
+ engines: { node: '>=12' }
+
+ is-generator-function@1.1.2:
+ resolution:
+ {
+ integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==,
+ }
+ engines: { node: '>= 0.4' }
is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==,
+ }
+ engines: { node: '>=0.10.0' }
is-interactive@1.0.0:
- resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==,
+ }
+ engines: { node: '>=8' }
is-interactive@2.0.0:
- resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==,
+ }
+ engines: { node: '>=12' }
is-lambda@1.0.1:
- resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
+ resolution:
+ {
+ integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==,
+ }
is-map@2.0.3:
- resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==,
+ }
+ engines: { node: '>= 0.4' }
+
+ is-negative-zero@2.0.3:
+ resolution:
+ {
+ integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==,
+ }
+ engines: { node: '>= 0.4' }
is-number-object@1.1.1:
- resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==,
+ }
+ engines: { node: '>= 0.4' }
is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
- is-obj@1.0.1:
- resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==,
+ }
+ engines: { node: '>=0.12.0' }
is-obj@2.0.0:
- resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==,
+ }
+ engines: { node: '>=8' }
is-path-inside@3.0.3:
- resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==,
+ }
+ engines: { node: '>=8' }
is-plain-obj@1.1.0:
- resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==,
+ }
+ engines: { node: '>=0.10.0' }
is-plain-object@2.0.4:
- resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
- engines: {node: '>=0.10.0'}
-
- is-plain-object@5.0.0:
- resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==,
+ }
+ engines: { node: '>=0.10.0' }
is-regex@1.2.1:
- resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
- engines: {node: '>= 0.4'}
-
- is-regexp@1.0.0:
- resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
- engines: {node: '>=0.10.0'}
-
- is-relative-path@1.0.2:
- resolution: {integrity: sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==}
+ resolution:
+ {
+ integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==,
+ }
+ engines: { node: '>= 0.4' }
is-set@2.0.3:
- resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==,
+ }
+ engines: { node: '>= 0.4' }
is-shared-array-buffer@1.0.4:
- resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
- engines: {node: '>= 0.4'}
-
- is-ssh@1.4.0:
- resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==}
+ resolution:
+ {
+ integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==,
+ }
+ engines: { node: '>= 0.4' }
+
+ is-ssh@1.4.1:
+ resolution:
+ {
+ integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==,
+ }
is-stream@2.0.0:
- resolution: {integrity: sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==}
- engines: {node: '>=8'}
-
- is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==,
+ }
+ engines: { node: '>=8' }
is-stream@3.0.0:
- resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
is-string@1.1.1:
- resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==,
+ }
+ engines: { node: '>= 0.4' }
is-symbol@1.1.1:
- resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==,
+ }
+ engines: { node: '>= 0.4' }
is-text-path@1.0.1:
- resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==,
+ }
+ engines: { node: '>=0.10.0' }
is-typed-array@1.1.15:
- resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==,
+ }
+ engines: { node: '>= 0.4' }
is-unicode-supported@0.1.0:
- resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==,
+ }
+ engines: { node: '>=10' }
is-unicode-supported@1.3.0:
- resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==,
+ }
+ engines: { node: '>=12' }
is-unicode-supported@2.1.0:
- resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
- engines: {node: '>=18'}
-
- is-url-superb@4.0.0:
- resolution: {integrity: sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==}
- engines: {node: '>=10'}
-
- is-url@1.2.4:
- resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
+ resolution:
+ {
+ integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==,
+ }
+ engines: { node: '>=18' }
is-weakmap@2.0.2:
- resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
- engines: {node: '>= 0.4'}
-
- is-weakref@1.1.0:
- resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==,
+ }
+ engines: { node: '>= 0.4' }
+
+ is-weakref@1.1.1:
+ resolution:
+ {
+ integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==,
+ }
+ engines: { node: '>= 0.4' }
is-weakset@2.0.4:
- resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==,
+ }
+ engines: { node: '>= 0.4' }
is-wsl@2.2.0:
- resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==,
+ }
+ engines: { node: '>=8' }
isarray@1.0.0:
- resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+ resolution:
+ {
+ integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==,
+ }
isarray@2.0.5:
- resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ resolution:
+ {
+ integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==,
+ }
isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ resolution:
+ {
+ integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==,
+ }
+
+ isexe@3.1.5:
+ resolution:
+ {
+ integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==,
+ }
+ engines: { node: '>=18' }
isobject@3.0.1:
- resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==,
+ }
+ engines: { node: '>=0.10.0' }
istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==,
+ }
+ engines: { node: '>=8' }
istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
-
- istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==,
+ }
+ engines: { node: '>=10' }
istanbul-lib-source-maps@5.0.6:
- resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
- engines: {node: '>=10'}
-
- istanbul-reports@3.1.7:
- resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==,
+ }
+ engines: { node: '>=10' }
+
+ istanbul-reports@3.2.0:
+ resolution:
+ {
+ integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==,
+ }
+ engines: { node: '>=8' }
jackspeak@3.4.3:
- resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
-
- jake@10.9.2:
- resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
- engines: {node: '>=10'}
- hasBin: true
-
- jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==,
+ }
+
+ jake@10.9.4:
+ resolution:
+ {
+ integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==,
+ }
+ engines: { node: '>=10' }
hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@types/node': '*'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- '@types/node':
- optional: true
- ts-node:
- optional: true
jest-diff@29.7.0:
- resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==,
+ }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-get-type@29.6.3:
- resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-matcher-utils@29.7.0:
- resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-message-util@29.7.0:
- resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
- peerDependencies:
- jest-resolve: '*'
- peerDependenciesMeta:
- jest-resolve:
- optional: true
-
- jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-util@29.7.0:
- resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jju@1.4.0:
- resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+ resolution:
+ {
+ integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==,
+ }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
+
+ js-levenshtein@1.1.6:
+ resolution:
+ {
+ integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==,
+ }
+ engines: { node: '>=0.10.0' }
+
+ js-tokens@10.0.0:
+ resolution:
+ {
+ integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==,
+ }
js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
- js-yaml@3.14.1:
- resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ resolution:
+ {
+ integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==,
+ }
+
+ js-tokens@9.0.1:
+ resolution:
+ {
+ integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==,
+ }
+
+ js-yaml@3.14.2:
+ resolution:
+ {
+ integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==,
+ }
hasBin: true
js-yaml@4.1.0:
- resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ resolution:
+ {
+ integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==,
+ }
hasBin: true
- jsbn@1.1.0:
- resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
-
- jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
+ js-yaml@4.1.1:
+ resolution:
+ {
+ integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==,
+ }
hasBin: true
json-buffer@3.0.1:
- resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ resolution:
+ {
+ integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==,
+ }
json-parse-better-errors@1.0.2:
- resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
+ resolution:
+ {
+ integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==,
+ }
json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ resolution:
+ {
+ integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==,
+ }
json-parse-even-better-errors@3.0.2:
- resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- json-schema-diff@0.18.1:
- resolution: {integrity: sha512-lLP/kbwXN85yKWwBGtraxVrJnK/v31D7UZIkSg68BrO+Qeai+aeW1u9b5H1h9uF/Uzzsa8PeaQPTYRaUcdAgWQ==}
- engines: {node: '>=v10.24.1'}
- hasBin: true
-
- json-schema-ref-parser@9.0.9:
- resolution: {integrity: sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==}
- engines: {node: '>=10'}
- deprecated: Please switch to @apidevtools/json-schema-ref-parser
-
- json-schema-spec-types@0.1.2:
- resolution: {integrity: sha512-MDl8fA8ONckmQOm2+eXKJaFJNvxk7eGin+XFofNjS3q3PRKSoEvgMVb0ehOpCAYkUiLoMiqdU7obV7AmzAmyLw==}
+ resolution:
+ {
+ integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
json-schema-traverse@0.4.1:
- resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ resolution:
+ {
+ integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==,
+ }
json-schema-traverse@1.0.0:
- resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+ resolution:
+ {
+ integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==,
+ }
+
+ json-schema-typed@8.0.2:
+ resolution:
+ {
+ integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==,
+ }
json-stable-stringify-without-jsonify@1.0.1:
- resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ resolution:
+ {
+ integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==,
+ }
- json-stringify-safe@5.0.1:
- resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+ json-stringify-nice@1.1.4:
+ resolution:
+ {
+ integrity: sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==,
+ }
- json-to-ast@2.1.0:
- resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==}
- engines: {node: '>= 4'}
+ json-stringify-safe@5.0.1:
+ resolution:
+ {
+ integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==,
+ }
json5@1.0.2:
- resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ resolution:
+ {
+ integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==,
+ }
hasBin: true
json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==,
+ }
+ engines: { node: '>=6' }
hasBin: true
jsonc-parser@3.2.0:
- resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
+ resolution:
+ {
+ integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==,
+ }
- jsonfile@4.0.0:
- resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
-
- jsonfile@6.1.0:
- resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ jsonfile@6.2.0:
+ resolution:
+ {
+ integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==,
+ }
jsonparse@1.3.1:
- resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
- engines: {'0': node >= 0.2.0}
-
- jsonpointer@5.0.1:
- resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==,
+ }
+ engines: { '0': node >= 0.2.0 }
+
+ just-diff-apply@5.5.0:
+ resolution:
+ {
+ integrity: sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==,
+ }
+
+ just-diff@6.0.2:
+ resolution:
+ {
+ integrity: sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==,
+ }
keyv@4.5.4:
- resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ resolution:
+ {
+ integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==,
+ }
kind-of@6.0.3:
- resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
- engines: {node: '>=0.10.0'}
-
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
-
- lerna@7.4.2:
- resolution: {integrity: sha512-gxavfzHfJ4JL30OvMunmlm4Anw7d7Tq6tdVHzUukLdS9nWnxCN/QB21qR+VJYp5tcyXogHKbdUEGh6qmeyzxSA==}
- engines: {node: '>=16.0.0'}
+ resolution:
+ {
+ integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==,
+ }
+ engines: { node: '>=0.10.0' }
+
+ lerna@8.2.4:
+ resolution:
+ {
+ integrity: sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==,
+ }
+ engines: { node: '>=18.0.0' }
hasBin: true
- leven@3.1.0:
- resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
- engines: {node: '>=6'}
-
levn@0.4.1:
- resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
- engines: {node: '>= 0.8.0'}
-
- libnpmaccess@7.0.2:
- resolution: {integrity: sha512-vHBVMw1JFMTgEk15zRsJuSAg7QtGGHpUSEfnbcRL1/gTBag9iEfJbyjpDmdJmwMhvpoLoNBtdAUCdGnaP32hhw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- libnpmpublish@7.3.0:
- resolution: {integrity: sha512-fHUxw5VJhZCNSls0KLNEG0mCD2PN1i14gH5elGOgiVnU3VgTcRahagYP2LKI1m0tFCJ+XrAm0zVYyF5RCbXzcg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==,
+ }
+ engines: { node: '>= 0.8.0' }
+
+ libnpmaccess@8.0.6:
+ resolution:
+ {
+ integrity: sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ libnpmpublish@9.0.9:
+ resolution:
+ {
+ integrity: sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
lilconfig@2.1.0:
- resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==,
+ }
+ engines: { node: '>=10' }
lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
-
- lines-and-columns@2.0.4:
- resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==,
+ }
+
+ lines-and-columns@2.0.3:
+ resolution:
+ {
+ integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
lint-staged@14.0.1:
- resolution: {integrity: sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==}
- engines: {node: ^16.14.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
hasBin: true
listr2@6.6.1:
- resolution: {integrity: sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==}
- engines: {node: '>=16.0.0'}
+ resolution:
+ {
+ integrity: sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==,
+ }
+ engines: { node: '>=16.0.0' }
peerDependencies:
enquirer: '>= 2.3.0 < 3'
peerDependenciesMeta:
@@ -3549,440 +4439,565 @@ packages:
optional: true
load-json-file@4.0.0:
- resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==,
+ }
+ engines: { node: '>=4' }
load-json-file@6.2.0:
- resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==,
+ }
+ engines: { node: '>=8' }
locate-path@2.0.0:
- resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==,
+ }
+ engines: { node: '>=4' }
locate-path@5.0.0:
- resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==,
+ }
+ engines: { node: '>=8' }
locate-path@6.0.0:
- resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
- engines: {node: '>=10'}
-
- lodash.clonedeep@4.5.0:
- resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
-
- lodash.get@4.4.2:
- resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
-
- lodash.isequal@4.5.0:
- resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ resolution:
+ {
+ integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==,
+ }
+ engines: { node: '>=10' }
lodash.ismatch@4.4.0:
- resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==}
-
- lodash.memoize@4.1.2:
- resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+ resolution:
+ {
+ integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==,
+ }
lodash.merge@4.6.2:
- resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ resolution:
+ {
+ integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==,
+ }
- lodash.truncate@4.4.2:
- resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
-
- lodash@4.17.21:
- resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ lodash@4.17.23:
+ resolution:
+ {
+ integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==,
+ }
log-symbols@4.1.0:
- resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==,
+ }
+ engines: { node: '>=10' }
log-symbols@6.0.0:
- resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==,
+ }
+ engines: { node: '>=18' }
log-update@5.0.1:
- resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
- loupe@3.1.2:
- resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
-
- lowercase-keys@3.0.0:
- resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
+
+ loupe@3.2.1:
+ resolution:
+ {
+ integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==,
+ }
lru-cache@10.4.3:
- resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
-
- lru-cache@4.1.5:
- resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
-
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ resolution:
+ {
+ integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==,
+ }
lru-cache@6.0.0:
- resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
- engines: {node: '>=10'}
-
- lru-cache@7.18.3:
- resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
- engines: {node: '>=12'}
-
- madge@7.0.0:
- resolution: {integrity: sha512-x9eHkBWoCJ2B8yGesWf8LRucarkbH5P3lazqgvmxe4xn5U2Meyfu906iG9mBB1RnY/f4D+gtELWdiz1k6+jAZA==}
- engines: {node: '>=14'}
- hasBin: true
- peerDependencies:
- typescript: ^3.9.5 || ^4.9.5 || ^5
- peerDependenciesMeta:
- typescript:
- optional: true
-
- magic-string@0.30.17:
- resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+ resolution:
+ {
+ integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==,
+ }
+ engines: { node: '>=10' }
+
+ magic-string@0.30.21:
+ resolution:
+ {
+ integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==,
+ }
magicast@0.3.5:
- resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+ resolution:
+ {
+ integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==,
+ }
make-dir@2.1.0:
- resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==,
+ }
+ engines: { node: '>=6' }
make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
-
- make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
- make-fetch-happen@10.2.1:
- resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
- make-fetch-happen@11.1.1:
- resolution: {integrity: sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ resolution:
+ {
+ integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==,
+ }
+ engines: { node: '>=10' }
+
+ make-fetch-happen@13.0.1:
+ resolution:
+ {
+ integrity: sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
map-obj@1.0.1:
- resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==,
+ }
+ engines: { node: '>=0.10.0' }
map-obj@4.3.0:
- resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==,
+ }
+ engines: { node: '>=8' }
math-intrinsics@1.1.0:
- resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==,
+ }
+ engines: { node: '>= 0.4' }
meow@8.1.2:
- resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==,
+ }
+ engines: { node: '>=10' }
merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ resolution:
+ {
+ integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==,
+ }
merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==,
+ }
+ engines: { node: '>= 8' }
micromatch@4.0.5:
- resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
- engines: {node: '>=8.6'}
+ resolution:
+ {
+ integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==,
+ }
+ engines: { node: '>=8.6' }
micromatch@4.0.8:
- resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
- engines: {node: '>=8.6'}
+ resolution:
+ {
+ integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==,
+ }
+ engines: { node: '>=8.6' }
mime-db@1.52.0:
- resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
- engines: {node: '>= 0.6'}
+ resolution:
+ {
+ integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==,
+ }
+ engines: { node: '>= 0.6' }
mime-types@2.1.35:
- resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
- engines: {node: '>= 0.6'}
+ resolution:
+ {
+ integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==,
+ }
+ engines: { node: '>= 0.6' }
mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==,
+ }
+ engines: { node: '>=6' }
mimic-fn@4.0.0:
- resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==,
+ }
+ engines: { node: '>=12' }
mimic-function@5.0.1:
- resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
- engines: {node: '>=18'}
-
- mimic-response@3.1.0:
- resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
- engines: {node: '>=10'}
-
- mimic-response@4.0.0:
- resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==,
+ }
+ engines: { node: '>=18' }
min-indent@1.0.1:
- resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==,
+ }
+ engines: { node: '>=4' }
minimatch@3.0.5:
- resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==}
+ resolution:
+ {
+ integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==,
+ }
minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ resolution:
+ {
+ integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==,
+ }
minimatch@5.1.6:
- resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==,
+ }
+ engines: { node: '>=10' }
minimatch@8.0.4:
- resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ {
+ integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
minimatch@9.0.3:
- resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ {
+ integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
minimatch@9.0.5:
- resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ {
+ integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
minimist-options@4.1.0:
- resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==,
+ }
+ engines: { node: '>= 6' }
minimist@1.2.8:
- resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-
- minipass-collect@1.0.2:
- resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
- engines: {node: '>= 8'}
-
- minipass-fetch@2.1.2:
- resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==,
+ }
+
+ minipass-collect@2.0.1:
+ resolution:
+ {
+ integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
minipass-fetch@3.0.5:
- resolution: {integrity: sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
minipass-flush@1.0.5:
- resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
- engines: {node: '>= 8'}
-
- minipass-json-stream@1.0.2:
- resolution: {integrity: sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==}
+ resolution:
+ {
+ integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==,
+ }
+ engines: { node: '>= 8' }
minipass-pipeline@1.2.4:
- resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==,
+ }
+ engines: { node: '>=8' }
minipass-sized@1.0.3:
- resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==,
+ }
+ engines: { node: '>=8' }
minipass@3.3.6:
- resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==,
+ }
+ engines: { node: '>=8' }
minipass@4.2.8:
- resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==,
+ }
+ engines: { node: '>=8' }
minipass@5.0.0:
- resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==,
+ }
+ engines: { node: '>=8' }
minipass@7.1.2:
- resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ {
+ integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==,
+ }
+ engines: { node: '>=16 || 14 >=14.17' }
minizlib@2.1.2:
- resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==,
+ }
+ engines: { node: '>= 8' }
mkdirp@1.0.4:
- resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==,
+ }
+ engines: { node: '>=10' }
hasBin: true
modify-values@1.0.1:
- resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
- engines: {node: '>=0.10.0'}
-
- module-definition@5.0.1:
- resolution: {integrity: sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA==}
- engines: {node: '>=14'}
- hasBin: true
-
- module-lookup-amd@8.0.5:
- resolution: {integrity: sha512-vc3rYLjDo5Frjox8NZpiyLXsNWJ5BWshztc/5KSOMzpg9k5cHH652YsJ7VKKmtM4SvaxuE9RkrYGhiSjH3Ehow==}
- engines: {node: '>=14'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==,
+ }
+ engines: { node: '>=0.10.0' }
ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ resolution:
+ {
+ integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==,
+ }
ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ resolution:
+ {
+ integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==,
+ }
multimatch@5.0.0:
- resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==}
- engines: {node: '>=10'}
-
- mustache@4.2.0:
- resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==,
+ }
+ engines: { node: '>=10' }
mute-stream@0.0.8:
- resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
+ resolution:
+ {
+ integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==,
+ }
mute-stream@1.0.0:
- resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- mute-stream@2.0.0:
- resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
- engines: {node: ^18.17.0 || >=20.5.0}
+ resolution:
+ {
+ integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ mute-stream@3.0.0:
+ resolution:
+ {
+ integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==,
+ }
+ engines: { node: ^20.17.0 || >=22.9.0 }
+
+ nanoid@3.3.11:
+ resolution:
+ {
+ integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==,
+ }
+ engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
+ hasBin: true
- nanoid@3.3.8:
- resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ napi-postinstall@0.3.4:
+ resolution:
+ {
+ integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==,
+ }
+ engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
hasBin: true
natural-compare@1.4.0:
- resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ resolution:
+ {
+ integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==,
+ }
negotiator@0.6.4:
- resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==}
- engines: {node: '>= 0.6'}
+ resolution:
+ {
+ integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==,
+ }
+ engines: { node: '>= 0.6' }
neo-async@2.6.2:
- resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
-
- node-addon-api@3.2.1:
- resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
+ resolution:
+ {
+ integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==,
+ }
node-fetch@2.6.7:
- resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
- engines: {node: 4.x || >=6.0.0}
+ resolution:
+ {
+ integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==,
+ }
+ engines: { node: 4.x || >=6.0.0 }
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
- node-gyp-build@4.8.4:
- resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
- hasBin: true
-
- node-gyp@9.4.1:
- resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==}
- engines: {node: ^12.13 || ^14.13 || >=16}
+ node-gyp@10.3.1:
+ resolution:
+ {
+ integrity: sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
hasBin: true
- node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-
node-machine-id@1.1.12:
- resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==}
-
- node-releases@2.0.19:
- resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
-
- node-source-walk@6.0.2:
- resolution: {integrity: sha512-jn9vOIK/nfqoFCcpK89/VCVaLg1IHE6UVfDOzvqmANaJ/rWCTEdH8RZ1V278nv2jr36BJdyQXIAavBLXpzdlag==}
- engines: {node: '>=14'}
-
- nopt@6.0.0:
- resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==,
+ }
+
+ nopt@7.2.1:
+ resolution:
+ {
+ integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
hasBin: true
normalize-package-data@2.5.0:
- resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+ resolution:
+ {
+ integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==,
+ }
normalize-package-data@3.0.3:
- resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
- engines: {node: '>=10'}
-
- normalize-package-data@5.0.0:
- resolution: {integrity: sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
-
- normalize-url@8.0.1:
- resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==}
- engines: {node: '>=14.16'}
-
- npm-bundled@1.1.2:
- resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==}
+ resolution:
+ {
+ integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==,
+ }
+ engines: { node: '>=10' }
+
+ normalize-package-data@6.0.2:
+ resolution:
+ {
+ integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
npm-bundled@3.0.1:
- resolution: {integrity: sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
npm-install-checks@6.3.0:
- resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- npm-normalize-package-bin@1.0.1:
- resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==}
+ resolution:
+ {
+ integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
npm-normalize-package-bin@3.0.1:
- resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- npm-package-arg@10.1.0:
- resolution: {integrity: sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- npm-package-arg@8.1.1:
- resolution: {integrity: sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==}
- engines: {node: '>=10'}
-
- npm-packlist@5.1.1:
- resolution: {integrity: sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- hasBin: true
-
- npm-packlist@7.0.4:
- resolution: {integrity: sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- npm-pick-manifest@8.0.2:
- resolution: {integrity: sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- npm-registry-fetch@14.0.5:
- resolution: {integrity: sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ npm-package-arg@11.0.2:
+ resolution:
+ {
+ integrity: sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ npm-packlist@8.0.2:
+ resolution:
+ {
+ integrity: sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ npm-pick-manifest@9.1.0:
+ resolution:
+ {
+ integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
+
+ npm-registry-fetch@17.1.0:
+ resolution:
+ {
+ integrity: sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==,
+ }
+ engines: { node: '>=8' }
npm-run-path@5.3.0:
- resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
- npmlog@6.0.2:
- resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
- nx@16.10.0:
- resolution: {integrity: sha512-gZl4iCC0Hx0Qe1VWmO4Bkeul2nttuXdPpfnlcDKSACGu3ZIo+uySqwOF8yBAxSTIf8xe2JRhgzJN1aFkuezEBg==}
+ resolution:
+ {
+ integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
+
+ nx@20.8.2:
+ resolution:
+ {
+ integrity: sha512-mDKpbH3vEpUFDx0rrLh+tTqLq1PYU8KiD/R7OVZGd1FxQxghx2HOl32MiqNsfPcw6AvKlXhslbwIESV+N55FLQ==,
+ }
hasBin: true
peerDependencies:
- '@swc-node/register': ^1.6.7
+ '@swc-node/register': ^1.8.0
'@swc/core': ^1.3.85
peerDependenciesMeta:
'@swc-node/register':
@@ -3990,354 +5005,515 @@ packages:
'@swc/core':
optional: true
- object-inspect@1.13.3:
- resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==}
- engines: {node: '>= 0.4'}
+ object-inspect@1.13.4:
+ resolution:
+ {
+ integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==,
+ }
+ engines: { node: '>= 0.4' }
object-keys@1.1.1:
- resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==,
+ }
+ engines: { node: '>= 0.4' }
object.assign@4.1.7:
- resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==,
+ }
+ engines: { node: '>= 0.4' }
object.fromentries@2.0.8:
- resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==,
+ }
+ engines: { node: '>= 0.4' }
object.groupby@1.0.3:
- resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==,
+ }
+ engines: { node: '>= 0.4' }
object.values@1.2.1:
- resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==,
+ }
+ engines: { node: '>= 0.4' }
once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ resolution:
+ {
+ integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==,
+ }
onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==,
+ }
+ engines: { node: '>=6' }
onetime@6.0.0:
- resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==,
+ }
+ engines: { node: '>=12' }
onetime@7.0.0:
- resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==,
+ }
+ engines: { node: '>=18' }
open@8.4.2:
- resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
- engines: {node: '>=12'}
-
- openapi-diff@0.23.7:
- resolution: {integrity: sha512-ABXJ7gTYyawmEC4Z3MiLu7CoD2fLSVfid+ttP9yiuDpytC2PDsc26OTNhYUV9y/z2/ama4CKbszkq3LMd80R6Q==}
- engines: {node: '>=6.11.4'}
- hasBin: true
-
- openapi-types@12.1.3:
- resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
-
- openapi-zod-client@1.18.2:
- resolution: {integrity: sha512-mfqBxwnGbnfK1CwQb6TBmu8CqVUlHD013Aw82JhDf0iGZsd5oemlPzO8QtteLAaAE6cmLNmSG/tQeBjQV0vB9g==}
- hasBin: true
-
- openapi3-ts@2.0.2:
- resolution: {integrity: sha512-TxhYBMoqx9frXyOgnRHufjQfPXomTIHYKhSKJ6jHfj13kS8OEIhvmE8CTuQyKtjjWttAjX5DPxM1vmalEpo8Qw==}
-
- openapi3-ts@3.1.0:
- resolution: {integrity: sha512-1qKTvCCVoV0rkwUh1zq5o8QyghmwYPuhdvtjv1rFjuOnJToXhQyF8eGjNETQ8QmGjr9Jz/tkAKLITIl2s7dw3A==}
-
- openapi3-ts@4.4.0:
- resolution: {integrity: sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==}
+ resolution:
+ {
+ integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==,
+ }
+ engines: { node: '>=12' }
optionator@0.9.4:
- resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ {
+ integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==,
+ }
+ engines: { node: '>= 0.8.0' }
+
+ ora@5.3.0:
+ resolution:
+ {
+ integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==,
+ }
+ engines: { node: '>=10' }
ora@5.4.1:
- resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
- engines: {node: '>=10'}
-
- ora@8.1.1:
- resolution: {integrity: sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==}
- engines: {node: '>=18'}
-
- os-tmpdir@1.0.2:
- resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==,
+ }
+ engines: { node: '>=10' }
+
+ ora@8.2.0:
+ resolution:
+ {
+ integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==,
+ }
+ engines: { node: '>=18' }
own-keys@1.0.1:
- resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
- engines: {node: '>= 0.4'}
-
- p-cancelable@3.0.0:
- resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
- engines: {node: '>=12.20'}
+ resolution:
+ {
+ integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==,
+ }
+ engines: { node: '>= 0.4' }
p-finally@1.0.0:
- resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==,
+ }
+ engines: { node: '>=4' }
p-limit@1.3.0:
- resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==,
+ }
+ engines: { node: '>=4' }
p-limit@2.3.0:
- resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==,
+ }
+ engines: { node: '>=6' }
p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==,
+ }
+ engines: { node: '>=10' }
p-locate@2.0.0:
- resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==,
+ }
+ engines: { node: '>=4' }
p-locate@4.1.0:
- resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==,
+ }
+ engines: { node: '>=8' }
p-locate@5.0.0:
- resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==,
+ }
+ engines: { node: '>=10' }
p-map-series@2.1.0:
- resolution: {integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==,
+ }
+ engines: { node: '>=8' }
p-map@4.0.0:
- resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==,
+ }
+ engines: { node: '>=10' }
p-pipe@3.1.0:
- resolution: {integrity: sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==,
+ }
+ engines: { node: '>=8' }
p-queue@6.6.2:
- resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==,
+ }
+ engines: { node: '>=8' }
p-reduce@2.1.0:
- resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==,
+ }
+ engines: { node: '>=8' }
p-timeout@3.2.0:
- resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==,
+ }
+ engines: { node: '>=8' }
p-try@1.0.0:
- resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==,
+ }
+ engines: { node: '>=4' }
p-try@2.2.0:
- resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==,
+ }
+ engines: { node: '>=6' }
p-waterfall@2.1.1:
- resolution: {integrity: sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==,
+ }
+ engines: { node: '>=8' }
package-json-from-dist@1.0.1:
- resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
-
- package-json@8.1.1:
- resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==}
- engines: {node: '>=14.16'}
-
- pacote@15.2.0:
- resolution: {integrity: sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==,
+ }
+
+ pacote@18.0.6:
+ resolution:
+ {
+ integrity: sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
hasBin: true
parent-module@1.0.1:
- resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
- engines: {node: '>=6'}
-
- parse-github-url@1.0.3:
- resolution: {integrity: sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww==}
- engines: {node: '>= 0.10'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==,
+ }
+ engines: { node: '>=6' }
+
+ parse-conflict-json@3.0.1:
+ resolution:
+ {
+ integrity: sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
parse-json@4.0.0:
- resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==,
+ }
+ engines: { node: '>=4' }
parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
-
- parse-ms@2.1.0:
- resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==}
- engines: {node: '>=6'}
-
- parse-path@7.0.0:
- resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==}
+ resolution:
+ {
+ integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==,
+ }
+ engines: { node: '>=8' }
+
+ parse-path@7.1.0:
+ resolution:
+ {
+ integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==,
+ }
parse-url@8.1.0:
- resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==}
-
- pastable@2.2.1:
- resolution: {integrity: sha512-K4ClMxRKpgN4sXj6VIPPrvor/TMp2yPNCGtfhvV106C73SwefQ3FuegURsH7AQHpqu0WwbvKXRl1HQxF6qax9w==}
- engines: {node: '>=14.x'}
- peerDependencies:
- react: '>=17'
- xstate: '>=4.32.1'
- peerDependenciesMeta:
- react:
- optional: true
- xstate:
- optional: true
+ resolution:
+ {
+ integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==,
+ }
path-exists@3.0.0:
- resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==,
+ }
+ engines: { node: '>=4' }
path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==,
+ }
+ engines: { node: '>=8' }
path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==,
+ }
+ engines: { node: '>=0.10.0' }
path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==,
+ }
+ engines: { node: '>=8' }
path-key@4.0.0:
- resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==,
+ }
+ engines: { node: '>=12' }
path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ resolution:
+ {
+ integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==,
+ }
path-scurry@1.11.1:
- resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
- engines: {node: '>=16 || 14 >=14.18'}
+ resolution:
+ {
+ integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==,
+ }
+ engines: { node: '>=16 || 14 >=14.18' }
path-type@3.0.0:
- resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==,
+ }
+ engines: { node: '>=4' }
path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
-
- path-type@5.0.0:
- resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==}
- engines: {node: '>=12'}
-
- pathe@2.0.2:
- resolution: {integrity: sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==}
-
- pathval@2.0.0:
- resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
- engines: {node: '>= 14.16'}
+ resolution:
+ {
+ integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==,
+ }
+ engines: { node: '>=8' }
+
+ pathe@2.0.3:
+ resolution:
+ {
+ integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==,
+ }
+
+ pathval@2.0.1:
+ resolution:
+ {
+ integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==,
+ }
+ engines: { node: '>= 14.16' }
picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ resolution:
+ {
+ integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==,
+ }
picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
+ resolution:
+ {
+ integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==,
+ }
+ engines: { node: '>=8.6' }
+
+ picomatch@4.0.3:
+ resolution:
+ {
+ integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==,
+ }
+ engines: { node: '>=12' }
pidtree@0.6.0:
- resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
- engines: {node: '>=0.10'}
+ resolution:
+ {
+ integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==,
+ }
+ engines: { node: '>=0.10' }
hasBin: true
pify@2.3.0:
- resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==,
+ }
+ engines: { node: '>=0.10.0' }
pify@3.0.0:
- resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==,
+ }
+ engines: { node: '>=4' }
pify@4.0.1:
- resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==,
+ }
+ engines: { node: '>=6' }
pify@5.0.0:
- resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==}
- engines: {node: '>=10'}
-
- pirates@4.0.6:
- resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==,
+ }
+ engines: { node: '>=10' }
pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==,
+ }
+ engines: { node: '>=8' }
pluralize@8.0.0:
- resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
- engines: {node: '>=4'}
-
- possible-typed-array-names@1.0.0:
- resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
- engines: {node: '>= 0.4'}
-
- postcss-values-parser@6.0.2:
- resolution: {integrity: sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==}
- engines: {node: '>=10'}
- peerDependencies:
- postcss: ^8.2.9
-
- postcss@8.5.1:
- resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==}
- engines: {node: ^10 || ^12 || >=14}
-
- precinct@11.0.5:
- resolution: {integrity: sha512-oHSWLC8cL/0znFhvln26D14KfCQFFn4KOLSw6hmLhd+LQ2SKt9Ljm89but76Pc7flM9Ty1TnXyrA2u16MfRV3w==}
- engines: {node: ^14.14.0 || >=16.0.0}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==,
+ }
+ engines: { node: '>=4' }
+
+ possible-typed-array-names@1.1.0:
+ resolution:
+ {
+ integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==,
+ }
+ engines: { node: '>= 0.4' }
+
+ postcss-selector-parser@6.1.2:
+ resolution:
+ {
+ integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==,
+ }
+ engines: { node: '>=4' }
+
+ postcss@8.5.6:
+ resolution:
+ {
+ integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==,
+ }
+ engines: { node: ^10 || ^12 || >=14 }
prelude-ls@1.2.1:
- resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
- engines: {node: '>= 0.8.0'}
-
- prettier-linter-helpers@1.0.0:
- resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
- engines: {node: '>=6.0.0'}
-
- prettier@2.8.8:
- resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
- engines: {node: '>=10.13.0'}
- hasBin: true
-
- prettier@3.3.3:
- resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
- engines: {node: '>=14'}
- hasBin: true
-
- prettier@3.4.2:
- resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==,
+ }
+ engines: { node: '>= 0.8.0' }
+
+ prettier-linter-helpers@1.0.1:
+ resolution:
+ {
+ integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==,
+ }
+ engines: { node: '>=6.0.0' }
+
+ prettier@3.8.1:
+ resolution:
+ {
+ integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==,
+ }
+ engines: { node: '>=14' }
hasBin: true
pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- pretty-ms@7.0.1:
- resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==}
- engines: {node: '>=10'}
-
- proc-log@3.0.0:
- resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==,
+ }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
+
+ proc-log@4.2.0:
+ resolution:
+ {
+ integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
process-nextick-args@2.0.1:
- resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ resolution:
+ {
+ integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==,
+ }
+
+ proggy@2.0.0:
+ resolution:
+ {
+ integrity: sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ promise-all-reject-late@1.0.1:
+ resolution:
+ {
+ integrity: sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==,
+ }
+
+ promise-call-limit@3.0.2:
+ resolution:
+ {
+ integrity: sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==,
+ }
promise-inflight@1.0.1:
- resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
+ resolution:
+ {
+ integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==,
+ }
peerDependencies:
bluebird: '*'
peerDependenciesMeta:
@@ -4345,907 +5521,1114 @@ packages:
optional: true
promise-retry@2.0.1:
- resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
- engines: {node: '>=10'}
-
- prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==,
+ }
+ engines: { node: '>=10' }
promzard@1.0.2:
- resolution: {integrity: sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- proto-list@1.2.4:
- resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
-
- protocols@2.0.1:
- resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==}
+ resolution:
+ {
+ integrity: sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ protocols@2.0.2:
+ resolution:
+ {
+ integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==,
+ }
proxy-from-env@1.1.0:
- resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
-
- pseudomap@1.0.2:
- resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
+ resolution:
+ {
+ integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==,
+ }
punycode@2.3.1:
- resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
- engines: {node: '>=6'}
-
- pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+ resolution:
+ {
+ integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==,
+ }
+ engines: { node: '>=6' }
queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ resolution:
+ {
+ integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==,
+ }
quick-lru@4.0.1:
- resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
- engines: {node: '>=8'}
-
- quick-lru@5.1.1:
- resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
- engines: {node: '>=10'}
-
- quote-unquote@1.0.0:
- resolution: {integrity: sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==}
-
- rc@1.2.8:
- resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==,
+ }
+ engines: { node: '>=8' }
react-is@18.3.1:
- resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ resolution:
+ {
+ integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==,
+ }
read-cmd-shim@4.0.0:
- resolution: {integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
read-package-json-fast@3.0.2:
- resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- read-package-json@6.0.4:
- resolution: {integrity: sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- deprecated: This package is no longer supported. Please use @npmcli/package-json instead.
+ resolution:
+ {
+ integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
read-pkg-up@3.0.0:
- resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==,
+ }
+ engines: { node: '>=4' }
read-pkg-up@7.0.1:
- resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==,
+ }
+ engines: { node: '>=8' }
read-pkg@3.0.0:
- resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==,
+ }
+ engines: { node: '>=4' }
read-pkg@5.2.0:
- resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
- engines: {node: '>=8'}
-
- read@2.1.0:
- resolution: {integrity: sha512-bvxi1QLJHcaywCAEsAk4DG3nVoqiY2Csps3qzWalhj5hFqRn1d/OixkFXtLO1PrgHUcAP0FNaSY/5GYNfENFFQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==,
+ }
+ engines: { node: '>=8' }
read@3.0.1:
- resolution: {integrity: sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
readable-stream@2.3.8:
- resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+ resolution:
+ {
+ integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==,
+ }
readable-stream@3.6.2:
- resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
- engines: {node: '>= 6'}
+ resolution:
+ {
+ integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==,
+ }
+ engines: { node: '>= 6' }
redent@3.0.0:
- resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==,
+ }
+ engines: { node: '>=8' }
reflect.getprototypeof@1.0.10:
- resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
- engines: {node: '>= 0.4'}
-
- regenerator-runtime@0.14.1:
- resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+ resolution:
+ {
+ integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==,
+ }
+ engines: { node: '>= 0.4' }
regexp.prototype.flags@1.5.4:
- resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
- engines: {node: '>= 0.4'}
-
- registry-auth-token@5.0.3:
- resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==}
- engines: {node: '>=14'}
-
- registry-url@6.0.1:
- resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==,
+ }
+ engines: { node: '>= 0.4' }
require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==,
+ }
+ engines: { node: '>=0.10.0' }
require-from-string@2.0.2:
- resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
- engines: {node: '>=0.10.0'}
-
- requirejs-config-file@4.0.0:
- resolution: {integrity: sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==}
- engines: {node: '>=10.13.0'}
-
- requirejs@2.3.7:
- resolution: {integrity: sha512-DouTG8T1WanGok6Qjg2SXuCMzszOo0eHeH9hDZ5Y4x8Je+9JB38HdTLT4/VA8OaUhBa0JPVHJ0pyBkM1z+pDsw==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
- resolve-alpn@1.2.1:
- resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+ resolution:
+ {
+ integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==,
+ }
+ engines: { node: '>=0.10.0' }
resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
-
- resolve-dependency-path@3.0.2:
- resolution: {integrity: sha512-Tz7zfjhLfsvR39ADOSk9us4421J/1ztVBo4rWUkF38hgHK5m0OCZ3NxFVpqHRkjctnwVa15igEUHFJp8MCS7vA==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==,
+ }
+ engines: { node: '>=8' }
resolve-from@4.0.0:
- resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==,
+ }
+ engines: { node: '>=4' }
resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==,
+ }
+ engines: { node: '>=8' }
resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ resolution:
+ {
+ integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==,
+ }
resolve.exports@2.0.3:
- resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
- engines: {node: '>=10'}
-
- resolve@1.22.10:
- resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==,
+ }
+ engines: { node: '>=10' }
+
+ resolve@1.22.11:
+ resolution:
+ {
+ integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==,
+ }
+ engines: { node: '>= 0.4' }
hasBin: true
- responselike@3.0.0:
- resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
- engines: {node: '>=14.16'}
-
restore-cursor@3.1.0:
- resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==,
+ }
+ engines: { node: '>=8' }
restore-cursor@4.0.0:
- resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==,
+ }
+ engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
restore-cursor@5.1.0:
- resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==,
+ }
+ engines: { node: '>=18' }
retry@0.12.0:
- resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
- engines: {node: '>= 4'}
-
- reusify@1.0.4:
- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==,
+ }
+ engines: { node: '>= 4' }
+
+ reusify@1.1.0:
+ resolution:
+ {
+ integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==,
+ }
+ engines: { iojs: '>=1.0.0', node: '>=0.10.0' }
rfdc@1.4.1:
- resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+ resolution:
+ {
+ integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==,
+ }
rimraf@3.0.2:
- resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
- deprecated: Rimraf versions prior to v4 are no longer supported
+ resolution:
+ {
+ integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==,
+ }
hasBin: true
rimraf@4.4.1:
- resolution: {integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==,
+ }
+ engines: { node: '>=14' }
hasBin: true
rimraf@5.0.10:
- resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
+ resolution:
+ {
+ integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==,
+ }
hasBin: true
- rollup@4.31.0:
- resolution: {integrity: sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==}
- engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ rollup@4.57.1:
+ resolution:
+ {
+ integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==,
+ }
+ engines: { node: '>=18.0.0', npm: '>=8.0.0' }
hasBin: true
run-async@2.4.1:
- resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
- engines: {node: '>=0.12.0'}
-
- run-async@3.0.0:
- resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==}
- engines: {node: '>=0.12.0'}
+ resolution:
+ {
+ integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==,
+ }
+ engines: { node: '>=0.12.0' }
run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ resolution:
+ {
+ integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==,
+ }
- rxjs@7.8.1:
- resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+ rxjs@7.8.2:
+ resolution:
+ {
+ integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==,
+ }
safe-array-concat@1.1.3:
- resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
- engines: {node: '>=0.4'}
+ resolution:
+ {
+ integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==,
+ }
+ engines: { node: '>=0.4' }
safe-buffer@5.1.2:
- resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ resolution:
+ {
+ integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==,
+ }
safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ resolution:
+ {
+ integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==,
+ }
safe-push-apply@1.0.0:
- resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==,
+ }
+ engines: { node: '>= 0.4' }
safe-regex-test@1.1.0:
- resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==,
+ }
+ engines: { node: '>= 0.4' }
safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
-
- sass-lookup@5.0.1:
- resolution: {integrity: sha512-t0X5PaizPc2H4+rCwszAqHZRtr4bugo4pgiCvrBFvIX0XFxnr29g77LJcpyj9A0DcKf7gXMLcgvRjsonYI6x4g==}
- engines: {node: '>=14'}
- hasBin: true
-
- sembear@0.5.2:
- resolution: {integrity: sha512-Ij1vCAdFgWABd7zTg50Xw1/p0JgESNxuLlneEAsmBrKishA06ulTTL/SHGmNy2Zud7+rKrHTKNI6moJsn1ppAQ==}
+ resolution:
+ {
+ integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==,
+ }
semver@5.7.2:
- resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+ resolution:
+ {
+ integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==,
+ }
hasBin: true
semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- semver@7.5.3:
- resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==,
+ }
hasBin: true
- semver@7.6.3:
- resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
- engines: {node: '>=10'}
+ semver@7.7.4:
+ resolution:
+ {
+ integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==,
+ }
+ engines: { node: '>=10' }
hasBin: true
set-blocking@2.0.0:
- resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+ resolution:
+ {
+ integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==,
+ }
set-function-length@1.2.2:
- resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==,
+ }
+ engines: { node: '>= 0.4' }
set-function-name@2.0.2:
- resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==,
+ }
+ engines: { node: '>= 0.4' }
set-proto@1.0.0:
- resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==,
+ }
+ engines: { node: '>= 0.4' }
shallow-clone@3.0.1:
- resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
- engines: {node: '>=8'}
-
- shebang-command@1.2.0:
- resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==,
+ }
+ engines: { node: '>=8' }
shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@1.0.0:
- resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==,
+ }
+ engines: { node: '>=8' }
shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==,
+ }
+ engines: { node: '>=8' }
side-channel-list@1.0.0:
- resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==,
+ }
+ engines: { node: '>= 0.4' }
side-channel-map@1.0.1:
- resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==,
+ }
+ engines: { node: '>= 0.4' }
side-channel-weakmap@1.0.2:
- resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==,
+ }
+ engines: { node: '>= 0.4' }
side-channel@1.1.0:
- resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==,
+ }
+ engines: { node: '>= 0.4' }
siginfo@2.0.0:
- resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+ resolution:
+ {
+ integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==,
+ }
signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ resolution:
+ {
+ integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==,
+ }
signal-exit@4.1.0:
- resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
- engines: {node: '>=14'}
-
- sigstore@1.9.0:
- resolution: {integrity: sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- hasBin: true
-
- sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ resolution:
+ {
+ integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==,
+ }
+ engines: { node: '>=14' }
+
+ sigstore@2.3.1:
+ resolution:
+ {
+ integrity: sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
-
- slash@5.1.0:
- resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
- engines: {node: '>=14.16'}
-
- slice-ansi@4.0.0:
- resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==,
+ }
+ engines: { node: '>=8' }
slice-ansi@5.0.0:
- resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==,
+ }
+ engines: { node: '>=12' }
smart-buffer@4.2.0:
- resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
- engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
-
- socks-proxy-agent@7.0.0:
- resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==}
- engines: {node: '>= 10'}
-
- socks@2.8.3:
- resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
- engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
+ resolution:
+ {
+ integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==,
+ }
+ engines: { node: '>= 6.0.0', npm: '>= 3.0.0' }
+
+ socks-proxy-agent@8.0.5:
+ resolution:
+ {
+ integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==,
+ }
+ engines: { node: '>= 14' }
+
+ socks@2.8.7:
+ resolution:
+ {
+ integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==,
+ }
+ engines: { node: '>= 10.0.0', npm: '>= 3.0.0' }
sort-keys@2.0.0:
- resolution: {integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==,
+ }
+ engines: { node: '>=4' }
source-map-js@1.2.1:
- resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
- engines: {node: '>=0.10.0'}
-
- source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+ resolution:
+ {
+ integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==,
+ }
+ engines: { node: '>=0.10.0' }
source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
- engines: {node: '>=0.10.0'}
-
- spawndamnit@2.0.0:
- resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
+ resolution:
+ {
+ integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==,
+ }
+ engines: { node: '>=0.10.0' }
spdx-correct@3.2.0:
- resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
+ resolution:
+ {
+ integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==,
+ }
spdx-exceptions@2.5.0:
- resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==}
+ resolution:
+ {
+ integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==,
+ }
spdx-expression-parse@3.0.1:
- resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+ resolution:
+ {
+ integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==,
+ }
- spdx-license-ids@3.0.21:
- resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}
+ spdx-license-ids@3.0.22:
+ resolution:
+ {
+ integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==,
+ }
split2@3.2.2:
- resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
+ resolution:
+ {
+ integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==,
+ }
split@1.0.1:
- resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==}
+ resolution:
+ {
+ integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==,
+ }
sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-
- sprintf-js@1.1.3:
- resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
+ resolution:
+ {
+ integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==,
+ }
ssri@10.0.6:
- resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- ssri@9.0.1:
- resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
- stable-hash@0.0.4:
- resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
-
- stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ stable-hash@0.0.5:
+ resolution:
+ {
+ integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==,
+ }
stackback@0.0.2:
- resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ resolution:
+ {
+ integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==,
+ }
- std-env@3.8.0:
- resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
+ std-env@3.10.0:
+ resolution:
+ {
+ integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==,
+ }
stdin-discarder@0.2.2:
- resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
- engines: {node: '>=18'}
-
- stream-to-array@2.3.0:
- resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==}
+ resolution:
+ {
+ integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==,
+ }
+ engines: { node: '>=18' }
+
+ stop-iteration-iterator@1.1.0:
+ resolution:
+ {
+ integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==,
+ }
+ engines: { node: '>= 0.4' }
string-argv@0.3.2:
- resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
- engines: {node: '>=0.6.19'}
-
- string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==,
+ }
+ engines: { node: '>=0.6.19' }
string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==,
+ }
+ engines: { node: '>=8' }
string-width@5.1.2:
- resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==,
+ }
+ engines: { node: '>=12' }
string-width@7.2.0:
- resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==,
+ }
+ engines: { node: '>=18' }
string.prototype.trim@1.2.10:
- resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==,
+ }
+ engines: { node: '>= 0.4' }
string.prototype.trimend@1.0.9:
- resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==,
+ }
+ engines: { node: '>= 0.4' }
string.prototype.trimstart@1.0.8:
- resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==,
+ }
+ engines: { node: '>= 0.4' }
string_decoder@1.1.1:
- resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ resolution:
+ {
+ integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==,
+ }
string_decoder@1.3.0:
- resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
-
- stringify-object@3.3.0:
- resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==,
+ }
strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
-
- strip-ansi@7.1.0:
- resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==,
+ }
+ engines: { node: '>=8' }
+
+ strip-ansi@7.1.2:
+ resolution:
+ {
+ integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==,
+ }
+ engines: { node: '>=12' }
strip-bom@3.0.0:
- resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==,
+ }
+ engines: { node: '>=4' }
strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==,
+ }
+ engines: { node: '>=8' }
strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==,
+ }
+ engines: { node: '>=6' }
strip-final-newline@3.0.0:
- resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==,
+ }
+ engines: { node: '>=12' }
strip-indent@3.0.0:
- resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
- engines: {node: '>=8'}
-
- strip-json-comments@2.0.1:
- resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==,
+ }
+ engines: { node: '>=8' }
strip-json-comments@3.1.1:
- resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
- engines: {node: '>=8'}
-
- strong-log-transformer@2.1.0:
- resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==}
- engines: {node: '>=4'}
- hasBin: true
-
- stylus-lookup@5.0.1:
- resolution: {integrity: sha512-tLtJEd5AGvnVy4f9UHQMw4bkJJtaAcmo54N+ovQBjDY3DuWyK9Eltxzr5+KG0q4ew6v2EHyuWWNnHeiw/Eo7rQ==}
- engines: {node: '>=14'}
- hasBin: true
-
- supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==,
+ }
+ engines: { node: '>=8' }
+
+ strip-literal@3.1.0:
+ resolution:
+ {
+ integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==,
+ }
supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
-
- supports-color@8.1.1:
- resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==,
+ }
+ engines: { node: '>=8' }
supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
-
- swagger-parser@10.0.3:
- resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==}
- engines: {node: '>=10'}
-
- synckit@0.9.2:
- resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
- engines: {node: ^14.18.0 || >=16.0.0}
-
- table@6.9.0:
- resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
- engines: {node: '>=10.0.0'}
-
- tanu@0.1.13:
- resolution: {integrity: sha512-UbRmX7ccZ4wMVOY/Uw+7ji4VOkEYSYJG1+I4qzbnn4qh/jtvVbrm6BFnF12NQQ4+jGv21wKmjb1iFyUSVnBWcQ==}
-
- tapable@2.2.1:
- resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==,
+ }
+ engines: { node: '>= 0.4' }
+
+ synckit@0.11.12:
+ resolution:
+ {
+ integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==,
+ }
+ engines: { node: ^14.18.0 || >=16.0.0 }
tar-stream@2.2.0:
- resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
- engines: {node: '>=6'}
-
- tar@6.1.11:
- resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
- engines: {node: '>= 10'}
-
- tar@6.2.0:
- resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==,
+ }
+ engines: { node: '>=6' }
+
+ tar@6.2.1:
+ resolution:
+ {
+ integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==,
+ }
+ engines: { node: '>=10' }
temp-dir@1.0.0:
- resolution: {integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==}
- engines: {node: '>=4'}
-
- temporal-polyfill@0.2.5:
- resolution: {integrity: sha512-ye47xp8Cb0nDguAhrrDS1JT1SzwEV9e26sSsrWzVu+yPZ7LzceEcH0i2gci9jWfOfSCCgM3Qv5nOYShVUUFUXA==}
-
- temporal-spec@0.2.4:
- resolution: {integrity: sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==}
-
- test-exclude@6.0.0:
- resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==,
+ }
+ engines: { node: '>=4' }
test-exclude@7.0.1:
- resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
- engines: {node: '>=18'}
+ resolution:
+ {
+ integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==,
+ }
+ engines: { node: '>=18' }
text-extensions@1.9.0:
- resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==}
- engines: {node: '>=0.10'}
+ resolution:
+ {
+ integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==,
+ }
+ engines: { node: '>=0.10' }
text-table@0.2.0:
- resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ resolution:
+ {
+ integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==,
+ }
through2@2.0.5:
- resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+ resolution:
+ {
+ integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==,
+ }
through@2.3.8:
- resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+ resolution:
+ {
+ integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==,
+ }
tinybench@2.9.0:
- resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+ resolution:
+ {
+ integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==,
+ }
tinyexec@0.3.2:
- resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
-
- tinypool@1.0.2:
- resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
- engines: {node: ^18.0.0 || >=20.0.0}
+ resolution:
+ {
+ integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==,
+ }
+
+ tinyglobby@0.2.12:
+ resolution:
+ {
+ integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==,
+ }
+ engines: { node: '>=12.0.0' }
+
+ tinyglobby@0.2.15:
+ resolution:
+ {
+ integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==,
+ }
+ engines: { node: '>=12.0.0' }
+
+ tinypool@1.1.1:
+ resolution:
+ {
+ integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==,
+ }
+ engines: { node: ^18.0.0 || >=20.0.0 }
tinyrainbow@2.0.0:
- resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
- engines: {node: '>=14.0.0'}
-
- tinyspy@3.0.2:
- resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
- engines: {node: '>=14.0.0'}
-
- tmp@0.0.33:
- resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
- engines: {node: '>=0.6.0'}
-
- tmp@0.2.3:
- resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
- engines: {node: '>=14.14'}
-
- tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+ resolution:
+ {
+ integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==,
+ }
+ engines: { node: '>=14.0.0' }
+
+ tinyspy@4.0.4:
+ resolution:
+ {
+ integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==,
+ }
+ engines: { node: '>=14.0.0' }
+
+ tmp@0.2.5:
+ resolution:
+ {
+ integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==,
+ }
+ engines: { node: '>=14.14' }
to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
+ resolution:
+ {
+ integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==,
+ }
+ engines: { node: '>=8.0' }
tr46@0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ resolution:
+ {
+ integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==,
+ }
+
+ treeverse@3.0.0:
+ resolution:
+ {
+ integrity: sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
trim-newlines@3.0.1:
- resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==,
+ }
+ engines: { node: '>=8' }
ts-api-utils@1.4.3:
- resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
- engines: {node: '>=16'}
+ resolution:
+ {
+ integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==,
+ }
+ engines: { node: '>=16' }
peerDependencies:
typescript: '>=4.2.0'
- ts-graphviz@1.8.2:
- resolution: {integrity: sha512-5YhbFoHmjxa7pgQLkB07MtGnGJ/yhvjmc9uhsnDBEICME6gkPf83SBwLDQqGDoCa3XzUMWLk1AU2Wn1u1naDtA==}
- engines: {node: '>=14.16'}
-
- ts-jest@29.2.5:
- resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==}
- engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@babel/core': '>=7.0.0-beta.0 <8'
- '@jest/transform': ^29.0.0
- '@jest/types': ^29.0.0
- babel-jest: ^29.0.0
- esbuild: '*'
- jest: ^29.0.0
- typescript: '>=4.3 <6'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@jest/transform':
- optional: true
- '@jest/types':
- optional: true
- babel-jest:
- optional: true
- esbuild:
- optional: true
-
- ts-node@10.9.2:
- resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
-
- ts-pattern@5.6.2:
- resolution: {integrity: sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==}
-
- ts-toolbelt@9.6.0:
- resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==}
-
tsconfig-paths@3.15.0:
- resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+ resolution:
+ {
+ integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==,
+ }
tsconfig-paths@4.2.0:
- resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
- engines: {node: '>=6'}
-
- tslib@1.14.1:
- resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ resolution:
+ {
+ integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==,
+ }
+ engines: { node: '>=6' }
tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
- tsutils@3.21.0:
- resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
- engines: {node: '>= 6'}
- peerDependencies:
- typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
-
- tuf-js@1.1.7:
- resolution: {integrity: sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==,
+ }
+
+ tuf-js@2.2.1:
+ resolution:
+ {
+ integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==,
+ }
+ engines: { node: ^16.14.0 || >=18.0.0 }
type-check@0.4.0:
- resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
- engines: {node: '>= 0.8.0'}
-
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
+ resolution:
+ {
+ integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==,
+ }
+ engines: { node: '>= 0.8.0' }
type-fest@0.18.1:
- resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==,
+ }
+ engines: { node: '>=10' }
type-fest@0.20.2:
- resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==,
+ }
+ engines: { node: '>=10' }
type-fest@0.21.3:
- resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==,
+ }
+ engines: { node: '>=10' }
type-fest@0.4.1:
- resolution: {integrity: sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==,
+ }
+ engines: { node: '>=6' }
type-fest@0.6.0:
- resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==,
+ }
+ engines: { node: '>=8' }
type-fest@0.8.1:
- resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==,
+ }
+ engines: { node: '>=8' }
type-fest@1.4.0:
- resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
- engines: {node: '>=10'}
-
- type-fest@3.13.1:
- resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
- engines: {node: '>=14.16'}
+ resolution:
+ {
+ integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==,
+ }
+ engines: { node: '>=10' }
typed-array-buffer@1.0.3:
- resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==,
+ }
+ engines: { node: '>= 0.4' }
typed-array-byte-length@1.0.3:
- resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==,
+ }
+ engines: { node: '>= 0.4' }
typed-array-byte-offset@1.0.4:
- resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==,
+ }
+ engines: { node: '>= 0.4' }
typed-array-length@1.0.7:
- resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==,
+ }
+ engines: { node: '>= 0.4' }
typedarray@0.0.6:
- resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
-
- typescript@4.9.5:
- resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
- engines: {node: '>=4.2.0'}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==,
+ }
typescript@5.7.3:
- resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
- engines: {node: '>=14.17'}
+ resolution:
+ {
+ integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==,
+ }
+ engines: { node: '>=14.17' }
hasBin: true
uglify-js@3.19.3:
- resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
- engines: {node: '>=0.8.0'}
+ resolution:
+ {
+ integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==,
+ }
+ engines: { node: '>=0.8.0' }
hasBin: true
unbox-primitive@1.1.0:
- resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
- engines: {node: '>= 0.4'}
-
- undici-types@6.20.0:
- resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
-
- unicorn-magic@0.1.0:
- resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
- engines: {node: '>=18'}
-
- unique-filename@2.0.1:
- resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==,
+ }
+ engines: { node: '>= 0.4' }
+
+ undici-types@6.21.0:
+ resolution:
+ {
+ integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==,
+ }
unique-filename@3.0.0:
- resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- unique-slug@3.0.0:
- resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
unique-slug@4.0.0:
- resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
universal-user-agent@6.0.1:
- resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
-
- universalify@0.1.2:
- resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
- engines: {node: '>= 4.0.0'}
+ resolution:
+ {
+ integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==,
+ }
universalify@2.0.1:
- resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
- engines: {node: '>= 10.0.0'}
+ resolution:
+ {
+ integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==,
+ }
+ engines: { node: '>= 10.0.0' }
+
+ unrs-resolver@1.11.1:
+ resolution:
+ {
+ integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==,
+ }
upath@2.0.1:
- resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==}
- engines: {node: '>=4'}
-
- update-browserslist-db@1.1.2:
- resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
+ resolution:
+ {
+ integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==,
+ }
+ engines: { node: '>=4' }
uri-js@4.4.1:
- resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ resolution:
+ {
+ integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==,
+ }
util-deprecate@1.0.2:
- resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-
- uuid@9.0.1:
- resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+ resolution:
+ {
+ integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==,
+ }
+
+ uuid@10.0.0:
+ resolution:
+ {
+ integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==,
+ }
hasBin: true
- v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
-
- v8-compile-cache@2.3.0:
- resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
-
- v8-to-istanbul@9.3.0:
- resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
- engines: {node: '>=10.12.0'}
-
validate-npm-package-license@3.0.4:
- resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
-
- validate-npm-package-name@3.0.0:
- resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==}
-
- validate-npm-package-name@5.0.0:
- resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
-
- validator@13.12.0:
- resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==}
- engines: {node: '>= 0.10'}
-
- verror@1.10.1:
- resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==}
- engines: {node: '>=0.6.0'}
-
- vite-node@3.0.3:
- resolution: {integrity: sha512-0sQcwhwAEw/UJGojbhOrnq3HtiZ3tC7BzpAa0lx3QaTX0S3YX70iGcik25UBdB96pmdwjyY2uyKNYruxCDmiEg==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ resolution:
+ {
+ integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==,
+ }
+
+ validate-npm-package-name@5.0.1:
+ resolution:
+ {
+ integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
+
+ vite-node@3.2.4:
+ resolution:
+ {
+ integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==,
+ }
+ engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 }
hasBin: true
- vite@6.0.11:
- resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ vite@7.3.1:
+ resolution:
+ {
+ integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==,
+ }
+ engines: { node: ^20.19.0 || >=22.12.0 }
hasBin: true
peerDependencies:
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@types/node': ^20.19.0 || >=22.12.0
jiti: '>=1.21.0'
- less: '*'
+ less: ^4.0.0
lightningcss: ^1.21.0
- sass: '*'
- sass-embedded: '*'
- stylus: '*'
- sugarss: '*'
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
@@ -5273,20 +6656,26 @@ packages:
yaml:
optional: true
- vitest@3.0.3:
- resolution: {integrity: sha512-dWdwTFUW9rcnL0LyF2F+IfvNQWB0w9DERySCk8VMG75F8k25C7LsZoh6XfCjPvcR8Nb+Lqi9JKr6vnzH7HSrpQ==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ vitest@3.2.4:
+ resolution:
+ {
+ integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==,
+ }
+ engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 }
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
+ '@types/debug': ^4.1.12
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- '@vitest/browser': 3.0.3
- '@vitest/ui': 3.0.3
+ '@vitest/browser': 3.2.4
+ '@vitest/ui': 3.2.4
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
+ '@types/debug':
+ optional: true
'@types/node':
optional: true
'@vitest/browser':
@@ -5298,554 +6687,372 @@ packages:
jsdom:
optional: true
- vscode-jsonrpc@8.2.0:
- resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
- engines: {node: '>=14.0.0'}
-
- vscode-languageserver-protocol@3.17.5:
- resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
-
- vscode-languageserver-textdocument@1.0.12:
- resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==}
-
- vscode-languageserver-types@3.17.5:
- resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
-
- vscode-languageserver@9.0.1:
- resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
- hasBin: true
-
- walkdir@0.4.1:
- resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==}
- engines: {node: '>=6.0.0'}
-
- walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+ walk-up-path@3.0.1:
+ resolution:
+ {
+ integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==,
+ }
wcwidth@1.0.1:
- resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ resolution:
+ {
+ integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==,
+ }
webidl-conversions@3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ resolution:
+ {
+ integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==,
+ }
whatwg-url@5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
-
- whence@2.0.1:
- resolution: {integrity: sha512-VtcCE1Pe3BKofF/k+P5xcpuoqQ0f1NJY6TmdUw5kInl9/pEr1ZEFD9+ZOUicf52tvpTbhMS93aWXriu2IQYTTw==}
- engines: {node: '>=14'}
+ resolution:
+ {
+ integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==,
+ }
which-boxed-primitive@1.1.1:
- resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==,
+ }
+ engines: { node: '>= 0.4' }
which-builtin-type@1.2.1:
- resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ {
+ integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==,
+ }
+ engines: { node: '>= 0.4' }
which-collection@1.0.2:
- resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
- engines: {node: '>= 0.4'}
-
- which-typed-array@1.1.18:
- resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==}
- engines: {node: '>= 0.4'}
-
- which@1.3.1:
- resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
- hasBin: true
+ resolution:
+ {
+ integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==,
+ }
+ engines: { node: '>= 0.4' }
+
+ which-typed-array@1.1.20:
+ resolution:
+ {
+ integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==,
+ }
+ engines: { node: '>= 0.4' }
which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
+ resolution:
+ {
+ integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==,
+ }
+ engines: { node: '>= 8' }
hasBin: true
- which@3.0.1:
- resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ which@4.0.0:
+ resolution:
+ {
+ integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==,
+ }
+ engines: { node: ^16.13.0 || >=18.0.0 }
hasBin: true
why-is-node-running@2.3.0:
- resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==,
+ }
+ engines: { node: '>=8' }
hasBin: true
wide-align@1.1.5:
- resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
+ resolution:
+ {
+ integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==,
+ }
word-wrap@1.2.5:
- resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ {
+ integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==,
+ }
+ engines: { node: '>=0.10.0' }
wordwrap@1.0.0:
- resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+ resolution:
+ {
+ integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==,
+ }
wrap-ansi@6.2.0:
- resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==,
+ }
+ engines: { node: '>=8' }
wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==,
+ }
+ engines: { node: '>=10' }
wrap-ansi@8.1.0:
- resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==,
+ }
+ engines: { node: '>=12' }
+
+ wrap-ansi@9.0.2:
+ resolution:
+ {
+ integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==,
+ }
+ engines: { node: '>=18' }
wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ resolution:
+ {
+ integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==,
+ }
write-file-atomic@2.4.3:
- resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==}
-
- write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ {
+ integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==,
+ }
write-file-atomic@5.0.1:
- resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ resolution:
+ {
+ integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==,
+ }
+ engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
write-json-file@3.2.0:
- resolution: {integrity: sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==,
+ }
+ engines: { node: '>=6' }
write-pkg@4.0.0:
- resolution: {integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==}
- engines: {node: '>=8'}
+ resolution:
+ {
+ integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==,
+ }
+ engines: { node: '>=8' }
xtend@4.0.2:
- resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
- engines: {node: '>=0.4'}
+ resolution:
+ {
+ integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==,
+ }
+ engines: { node: '>=0.4' }
y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
-
- yallist@2.1.2:
- resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
-
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ resolution:
+ {
+ integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==,
+ }
+ engines: { node: '>=10' }
yallist@4.0.0:
- resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ resolution:
+ {
+ integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==,
+ }
- yaml@1.10.2:
- resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
- engines: {node: '>= 6'}
+ yaml-ast-parser@0.0.43:
+ resolution:
+ {
+ integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==,
+ }
yaml@2.3.1:
- resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
- engines: {node: '>= 14'}
-
- yaml@2.5.1:
- resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==}
- engines: {node: '>= 14'}
- hasBin: true
-
- yaml@2.7.0:
- resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
- engines: {node: '>= 14'}
+ resolution:
+ {
+ integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==,
+ }
+ engines: { node: '>= 14' }
+
+ yaml@2.8.2:
+ resolution:
+ {
+ integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==,
+ }
+ engines: { node: '>= 14.6' }
hasBin: true
- yargs-parser@20.2.4:
- resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==}
- engines: {node: '>=10'}
-
yargs-parser@20.2.9:
- resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==,
+ }
+ engines: { node: '>=10' }
yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
+ resolution:
+ {
+ integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==,
+ }
+ engines: { node: '>=12' }
yargs@16.2.0:
- resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
- engines: {node: '>=10'}
+ resolution:
+ {
+ integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==,
+ }
+ engines: { node: '>=10' }
yargs@17.7.2:
- resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
- engines: {node: '>=12'}
-
- yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
+ resolution:
+ {
+ integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==,
+ }
+ engines: { node: '>=12' }
yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
-
- yoctocolors-cjs@2.1.2:
- resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==}
- engines: {node: '>=18'}
-
- z-schema@5.0.5:
- resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
- engines: {node: '>=8.0.0'}
- hasBin: true
-
- zod@3.24.1:
- resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
+ resolution:
+ {
+ integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==,
+ }
+ engines: { node: '>=10' }
snapshots:
-
'@ampproject/remapping@2.3.0':
dependencies:
- '@jridgewell/gen-mapping': 0.3.8
- '@jridgewell/trace-mapping': 0.3.25
-
- '@apidevtools/json-schema-ref-parser@11.7.2':
- dependencies:
- '@jsdevtools/ono': 7.1.3
- '@types/json-schema': 7.0.15
- js-yaml: 4.1.0
-
- '@apidevtools/json-schema-ref-parser@9.0.9':
- dependencies:
- '@jsdevtools/ono': 7.1.3
- '@types/json-schema': 7.0.15
- call-me-maybe: 1.0.2
- js-yaml: 4.1.0
-
- '@apidevtools/json-schema-ref-parser@9.1.2':
- dependencies:
- '@jsdevtools/ono': 7.1.3
- '@types/json-schema': 7.0.15
- call-me-maybe: 1.0.2
- js-yaml: 4.1.0
-
- '@apidevtools/openapi-schemas@2.1.0': {}
-
- '@apidevtools/swagger-methods@3.0.2': {}
-
- '@apidevtools/swagger-parser@10.0.3(openapi-types@12.1.3)':
- dependencies:
- '@apidevtools/json-schema-ref-parser': 9.1.2
- '@apidevtools/openapi-schemas': 2.1.0
- '@apidevtools/swagger-methods': 3.0.2
- '@jsdevtools/ono': 7.1.3
- call-me-maybe: 1.0.2
- openapi-types: 12.1.3
- z-schema: 5.0.5
-
- '@apidevtools/swagger-parser@10.1.1(openapi-types@12.1.3)':
- dependencies:
- '@apidevtools/json-schema-ref-parser': 11.7.2
- '@apidevtools/openapi-schemas': 2.1.0
- '@apidevtools/swagger-methods': 3.0.2
- '@jsdevtools/ono': 7.1.3
- ajv: 8.17.1
- ajv-draft-04: 1.0.0(ajv@8.17.1)
- call-me-maybe: 1.0.2
- openapi-types: 12.1.3
-
- '@babel/code-frame@7.25.9':
- dependencies:
- '@babel/highlight': 7.25.9
- picocolors: 1.1.1
-
- '@babel/code-frame@7.26.2':
- dependencies:
- '@babel/helper-validator-identifier': 7.25.9
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.26.5': {}
-
- '@babel/core@7.26.0':
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.26.2
- '@babel/generator': 7.26.5
- '@babel/helper-compilation-targets': 7.26.5
- '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0)
- '@babel/helpers': 7.26.0
- '@babel/parser': 7.26.5
- '@babel/template': 7.25.9
- '@babel/traverse': 7.26.5
- '@babel/types': 7.26.5
- convert-source-map: 2.0.0
- debug: 4.4.0
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.26.5':
- dependencies:
- '@babel/parser': 7.26.5
- '@babel/types': 7.26.5
- '@jridgewell/gen-mapping': 0.3.8
- '@jridgewell/trace-mapping': 0.3.25
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.26.5':
- dependencies:
- '@babel/compat-data': 7.26.5
- '@babel/helper-validator-option': 7.25.9
- browserslist: 4.24.4
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-module-imports@7.25.9':
- dependencies:
- '@babel/traverse': 7.26.5
- '@babel/types': 7.26.5
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-module-imports': 7.25.9
- '@babel/helper-validator-identifier': 7.25.9
- '@babel/traverse': 7.26.5
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-plugin-utils@7.26.5': {}
-
- '@babel/helper-string-parser@7.25.9': {}
-
- '@babel/helper-validator-identifier@7.25.9': {}
-
- '@babel/helper-validator-option@7.25.9': {}
-
- '@babel/helpers@7.26.0':
- dependencies:
- '@babel/template': 7.25.9
- '@babel/types': 7.26.5
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
- '@babel/highlight@7.25.9':
+ '@babel/code-frame@7.29.0':
dependencies:
- '@babel/helper-validator-identifier': 7.25.9
- chalk: 2.4.2
+ '@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
- '@babel/parser@7.26.5':
- dependencies:
- '@babel/types': 7.26.5
-
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
+ '@babel/helper-string-parser@7.27.1': {}
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)':
- dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
+ '@babel/helper-validator-identifier@7.28.5': {}
- '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)':
+ '@babel/parser@7.29.0':
dependencies:
- '@babel/core': 7.26.0
- '@babel/helper-plugin-utils': 7.26.5
+ '@babel/types': 7.29.0
- '@babel/runtime@7.26.0':
+ '@babel/types@7.29.0':
dependencies:
- regenerator-runtime: 0.14.1
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
- '@babel/template@7.25.9':
- dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/parser': 7.26.5
- '@babel/types': 7.26.5
+ '@bcoe/v8-coverage@1.0.2': {}
- '@babel/traverse@7.26.5':
+ '@emnapi/core@1.8.1':
dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/generator': 7.26.5
- '@babel/parser': 7.26.5
- '@babel/template': 7.25.9
- '@babel/types': 7.26.5
- debug: 4.4.0
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
- '@babel/types@7.26.5':
+ '@emnapi/runtime@1.8.1':
dependencies:
- '@babel/helper-string-parser': 7.25.9
- '@babel/helper-validator-identifier': 7.25.9
-
- '@bcoe/v8-coverage@0.2.3': {}
-
- '@bcoe/v8-coverage@1.0.2': {}
+ tslib: 2.8.1
- '@cspotcode/source-map-support@0.8.1':
+ '@emnapi/wasi-threads@1.1.0':
dependencies:
- '@jridgewell/trace-mapping': 0.3.9
+ tslib: 2.8.1
- '@dependents/detective-less@4.1.0':
- dependencies:
- gonzales-pe: 4.3.0
- node-source-walk: 6.0.2
+ '@esbuild/aix-ppc64@0.27.3':
+ optional: true
- '@esbuild/aix-ppc64@0.24.2':
+ '@esbuild/android-arm64@0.27.3':
optional: true
- '@esbuild/android-arm64@0.24.2':
+ '@esbuild/android-arm@0.27.3':
optional: true
- '@esbuild/android-arm@0.24.2':
+ '@esbuild/android-x64@0.27.3':
optional: true
- '@esbuild/android-x64@0.24.2':
+ '@esbuild/darwin-arm64@0.27.3':
optional: true
- '@esbuild/darwin-arm64@0.24.2':
+ '@esbuild/darwin-x64@0.27.3':
optional: true
- '@esbuild/darwin-x64@0.24.2':
+ '@esbuild/freebsd-arm64@0.27.3':
optional: true
- '@esbuild/freebsd-arm64@0.24.2':
+ '@esbuild/freebsd-x64@0.27.3':
optional: true
- '@esbuild/freebsd-x64@0.24.2':
+ '@esbuild/linux-arm64@0.27.3':
optional: true
- '@esbuild/linux-arm64@0.24.2':
+ '@esbuild/linux-arm@0.27.3':
optional: true
- '@esbuild/linux-arm@0.24.2':
+ '@esbuild/linux-ia32@0.27.3':
optional: true
- '@esbuild/linux-ia32@0.24.2':
+ '@esbuild/linux-loong64@0.27.3':
optional: true
- '@esbuild/linux-loong64@0.24.2':
+ '@esbuild/linux-mips64el@0.27.3':
optional: true
- '@esbuild/linux-mips64el@0.24.2':
+ '@esbuild/linux-ppc64@0.27.3':
optional: true
- '@esbuild/linux-ppc64@0.24.2':
+ '@esbuild/linux-riscv64@0.27.3':
optional: true
- '@esbuild/linux-riscv64@0.24.2':
+ '@esbuild/linux-s390x@0.27.3':
optional: true
- '@esbuild/linux-s390x@0.24.2':
+ '@esbuild/linux-x64@0.27.3':
optional: true
- '@esbuild/linux-x64@0.24.2':
+ '@esbuild/netbsd-arm64@0.27.3':
optional: true
- '@esbuild/netbsd-arm64@0.24.2':
+ '@esbuild/netbsd-x64@0.27.3':
optional: true
- '@esbuild/netbsd-x64@0.24.2':
+ '@esbuild/openbsd-arm64@0.27.3':
optional: true
- '@esbuild/openbsd-arm64@0.24.2':
+ '@esbuild/openbsd-x64@0.27.3':
optional: true
- '@esbuild/openbsd-x64@0.24.2':
+ '@esbuild/openharmony-arm64@0.27.3':
optional: true
- '@esbuild/sunos-x64@0.24.2':
+ '@esbuild/sunos-x64@0.27.3':
optional: true
- '@esbuild/win32-arm64@0.24.2':
+ '@esbuild/win32-arm64@0.27.3':
optional: true
- '@esbuild/win32-ia32@0.24.2':
+ '@esbuild/win32-ia32@0.27.3':
optional: true
- '@esbuild/win32-x64@0.24.2':
+ '@esbuild/win32-x64@0.27.3':
optional: true
- '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)':
+ '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)':
dependencies:
eslint: 8.57.1
eslint-visitor-keys: 3.4.3
- '@eslint-community/regexpp@4.12.1': {}
+ '@eslint-community/regexpp@4.12.2': {}
'@eslint/eslintrc@2.1.4':
dependencies:
ajv: 6.12.6
- debug: 4.4.0
+ debug: 4.4.3
espree: 9.6.1
globals: 13.24.0
ignore: 5.3.2
- import-fresh: 3.3.0
- js-yaml: 4.1.0
+ import-fresh: 3.3.1
+ js-yaml: 4.1.1
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -5853,452 +7060,271 @@ snapshots:
'@eslint/js@8.57.1': {}
- '@gar/promisify@1.1.3': {}
-
- '@humanwhocodes/config-array@0.13.0':
- dependencies:
- '@humanwhocodes/object-schema': 2.0.3
- debug: 4.4.0
- minimatch: 3.1.2
- transitivePeerDependencies:
- - supports-color
-
- '@humanwhocodes/module-importer@1.0.1': {}
-
- '@humanwhocodes/momoa@2.0.4': {}
-
- '@humanwhocodes/object-schema@2.0.3': {}
-
- '@hutson/parse-repository-url@3.0.2': {}
-
- '@inquirer/checkbox@4.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/figures': 1.0.9
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
- yoctocolors-cjs: 2.1.2
-
- '@inquirer/confirm@5.1.3(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
-
- '@inquirer/core@10.1.4(@types/node@22.10.7)':
- dependencies:
- '@inquirer/figures': 1.0.9
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- ansi-escapes: 4.3.2
- cli-width: 4.1.0
- mute-stream: 2.0.0
- signal-exit: 4.1.0
- strip-ansi: 6.0.1
- wrap-ansi: 6.2.0
- yoctocolors-cjs: 2.1.2
- transitivePeerDependencies:
- - '@types/node'
-
- '@inquirer/editor@4.2.3(@types/node@22.10.7)':
+ '@humanwhocodes/config-array@0.13.0':
dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- external-editor: 3.1.0
+ '@humanwhocodes/object-schema': 2.0.3
+ debug: 4.4.3
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
- '@inquirer/expand@4.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- yoctocolors-cjs: 2.1.2
+ '@humanwhocodes/module-importer@1.0.1': {}
- '@inquirer/figures@1.0.9': {}
+ '@humanwhocodes/object-schema@2.0.3': {}
- '@inquirer/input@4.1.3(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
+ '@hutson/parse-repository-url@3.0.2': {}
- '@inquirer/number@3.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
+ '@inquirer/ansi@2.0.2': {}
- '@inquirer/password@4.0.6(@types/node@22.10.7)':
+ '@inquirer/checkbox@5.0.3(@types/node@22.19.11)':
dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
-
- '@inquirer/prompts@7.2.3(@types/node@22.10.7)':
- dependencies:
- '@inquirer/checkbox': 4.0.6(@types/node@22.10.7)
- '@inquirer/confirm': 5.1.3(@types/node@22.10.7)
- '@inquirer/editor': 4.2.3(@types/node@22.10.7)
- '@inquirer/expand': 4.0.6(@types/node@22.10.7)
- '@inquirer/input': 4.1.3(@types/node@22.10.7)
- '@inquirer/number': 3.0.6(@types/node@22.10.7)
- '@inquirer/password': 4.0.6(@types/node@22.10.7)
- '@inquirer/rawlist': 4.0.6(@types/node@22.10.7)
- '@inquirer/search': 3.0.6(@types/node@22.10.7)
- '@inquirer/select': 4.0.6(@types/node@22.10.7)
- '@types/node': 22.10.7
-
- '@inquirer/rawlist@4.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- yoctocolors-cjs: 2.1.2
-
- '@inquirer/search@3.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/figures': 1.0.9
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- yoctocolors-cjs: 2.1.2
-
- '@inquirer/select@4.0.6(@types/node@22.10.7)':
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/figures': 1.0.9
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
- yoctocolors-cjs: 2.1.2
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@inquirer/type@3.0.2(@types/node@22.10.7)':
+ '@inquirer/confirm@6.0.3(@types/node@22.19.11)':
dependencies:
- '@types/node': 22.10.7
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@isaacs/cliui@8.0.2':
+ '@inquirer/core@11.1.0(@types/node@22.19.11)':
dependencies:
- string-width: 5.1.2
- string-width-cjs: string-width@4.2.3
- strip-ansi: 7.1.0
- strip-ansi-cjs: strip-ansi@6.0.1
- wrap-ansi: 8.1.0
- wrap-ansi-cjs: wrap-ansi@7.0.0
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ cli-width: 4.1.0
+ mute-stream: 3.0.0
+ signal-exit: 4.1.0
+ wrap-ansi: 9.0.2
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@istanbuljs/load-nyc-config@1.1.0':
+ '@inquirer/editor@5.0.3(@types/node@22.19.11)':
dependencies:
- camelcase: 5.3.1
- find-up: 4.1.0
- get-package-type: 0.1.0
- js-yaml: 3.14.1
- resolve-from: 5.0.0
-
- '@istanbuljs/schema@0.1.3': {}
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/external-editor': 2.0.2(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/console@29.7.0':
+ '@inquirer/expand@5.0.3(@types/node@22.19.11)':
dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- chalk: 4.1.2
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))':
+ '@inquirer/external-editor@1.0.3(@types/node@22.19.11)':
dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
+ chardet: 2.1.1
+ iconv-lite: 0.7.2
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/environment@29.7.0':
+ '@inquirer/external-editor@2.0.2(@types/node@22.19.11)':
dependencies:
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- jest-mock: 29.7.0
+ chardet: 2.1.1
+ iconv-lite: 0.7.2
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/expect-utils@29.7.0':
- dependencies:
- jest-get-type: 29.6.3
+ '@inquirer/figures@2.0.2': {}
- '@jest/expect@29.7.0':
+ '@inquirer/input@5.0.3(@types/node@22.19.11)':
dependencies:
- expect: 29.7.0
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/fake-timers@29.7.0':
+ '@inquirer/number@4.0.3(@types/node@22.19.11)':
dependencies:
- '@jest/types': 29.6.3
- '@sinonjs/fake-timers': 10.3.0
- '@types/node': 22.10.7
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/globals@29.7.0':
+ '@inquirer/password@5.0.3(@types/node@22.19.11)':
dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/types': 29.6.3
- jest-mock: 29.7.0
- transitivePeerDependencies:
- - supports-color
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
+
+ '@inquirer/prompts@8.1.0(@types/node@22.19.11)':
+ dependencies:
+ '@inquirer/checkbox': 5.0.3(@types/node@22.19.11)
+ '@inquirer/confirm': 6.0.3(@types/node@22.19.11)
+ '@inquirer/editor': 5.0.3(@types/node@22.19.11)
+ '@inquirer/expand': 5.0.3(@types/node@22.19.11)
+ '@inquirer/input': 5.0.3(@types/node@22.19.11)
+ '@inquirer/number': 4.0.3(@types/node@22.19.11)
+ '@inquirer/password': 5.0.3(@types/node@22.19.11)
+ '@inquirer/rawlist': 5.1.0(@types/node@22.19.11)
+ '@inquirer/search': 4.0.3(@types/node@22.19.11)
+ '@inquirer/select': 5.0.3(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/reporters@29.7.0':
+ '@inquirer/rawlist@5.1.0(@types/node@22.19.11)':
dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@jest/console': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- '@types/node': 22.10.7
- chalk: 4.1.2
- collect-v8-coverage: 1.0.2
- exit: 0.1.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-instrument: 6.0.3
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.1.7
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- jest-worker: 29.7.0
- slash: 3.0.0
- string-length: 4.0.2
- strip-ansi: 6.0.1
- v8-to-istanbul: 9.3.0
- transitivePeerDependencies:
- - supports-color
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/schemas@29.6.3':
+ '@inquirer/search@4.0.3(@types/node@22.19.11)':
dependencies:
- '@sinclair/typebox': 0.27.8
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/source-map@29.6.3':
+ '@inquirer/select@5.0.3(@types/node@22.19.11)':
dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- callsites: 3.1.0
- graceful-fs: 4.2.11
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.1.0(@types/node@22.19.11)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@22.19.11)
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/test-result@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/types': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- collect-v8-coverage: 1.0.2
+ '@inquirer/type@4.0.2(@types/node@22.19.11)':
+ optionalDependencies:
+ '@types/node': 22.19.11
- '@jest/test-sequencer@29.7.0':
+ '@isaacs/cliui@8.0.2':
dependencies:
- '@jest/test-result': 29.7.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- slash: 3.0.0
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.2
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
- '@jest/transform@29.7.0':
- dependencies:
- '@babel/core': 7.26.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- babel-plugin-istanbul: 6.1.1
- chalk: 4.1.2
- convert-source-map: 2.0.0
- fast-json-stable-stringify: 2.1.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- micromatch: 4.0.8
- pirates: 4.0.6
- slash: 3.0.0
- write-file-atomic: 4.0.2
- transitivePeerDependencies:
- - supports-color
+ '@isaacs/string-locale-compare@1.1.0': {}
+
+ '@istanbuljs/schema@0.1.3': {}
- '@jest/types@29.6.3':
+ '@jest/schemas@29.6.3':
dependencies:
- '@jest/schemas': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- '@types/istanbul-reports': 3.0.4
- '@types/node': 22.10.7
- '@types/yargs': 17.0.33
- chalk: 4.1.2
+ '@sinclair/typebox': 0.27.8
- '@jridgewell/gen-mapping@0.3.8':
+ '@jridgewell/gen-mapping@0.3.13':
dependencies:
- '@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.5.0
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.2': {}
- '@jridgewell/set-array@1.2.1': {}
-
- '@jridgewell/sourcemap-codec@1.5.0': {}
-
- '@jridgewell/trace-mapping@0.3.25':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/sourcemap-codec@1.5.5': {}
- '@jridgewell/trace-mapping@0.3.9':
+ '@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.0
-
- '@jsdevtools/ono@7.1.3': {}
-
- '@lerna/child-process@7.4.2':
- dependencies:
- chalk: 4.1.2
- execa: 5.0.0
- strong-log-transformer: 2.1.0
+ '@jridgewell/sourcemap-codec': 1.5.5
- '@lerna/create@7.4.2(encoding@0.1.13)(typescript@5.7.3)':
+ '@lerna/create@8.2.4(@types/node@22.19.11)(encoding@0.1.13)(typescript@5.7.3)':
dependencies:
- '@lerna/child-process': 7.4.2
- '@npmcli/run-script': 6.0.2
- '@nx/devkit': 16.10.0(nx@16.10.0)
+ '@npmcli/arborist': 7.5.4
+ '@npmcli/package-json': 5.2.0
+ '@npmcli/run-script': 8.1.0
+ '@nx/devkit': 20.8.2(nx@20.8.2)
'@octokit/plugin-enterprise-rest': 6.0.1
- '@octokit/rest': 19.0.11(encoding@0.1.13)
+ '@octokit/rest': 20.1.2
+ aproba: 2.0.0
byte-size: 8.1.1
chalk: 4.1.0
clone-deep: 4.0.1
- cmd-shim: 6.0.1
+ cmd-shim: 6.0.3
+ color-support: 1.1.3
columnify: 1.6.0
+ console-control-strings: 1.1.0
conventional-changelog-core: 5.0.1
conventional-recommended-bump: 7.0.1
- cosmiconfig: 8.3.6(typescript@5.7.3)
- dedent: 0.7.0
+ cosmiconfig: 9.0.0(typescript@5.7.3)
+ dedent: 1.5.3
execa: 5.0.0
- fs-extra: 11.3.0
+ fs-extra: 11.3.3
get-stream: 6.0.0
- git-url-parse: 13.1.0
- glob-parent: 5.1.2
- globby: 11.1.0
+ git-url-parse: 14.0.0
+ glob-parent: 6.0.2
graceful-fs: 4.2.11
has-unicode: 2.0.1
ini: 1.3.8
- init-package-json: 5.0.0
- inquirer: 8.2.6
+ init-package-json: 6.0.3
+ inquirer: 8.2.7(@types/node@22.19.11)
is-ci: 3.0.1
is-stream: 2.0.0
js-yaml: 4.1.0
- libnpmpublish: 7.3.0
+ libnpmpublish: 9.0.9
load-json-file: 6.2.0
- lodash: 4.17.21
make-dir: 4.0.0
minimatch: 3.0.5
multimatch: 5.0.0
node-fetch: 2.6.7(encoding@0.1.13)
- npm-package-arg: 8.1.1
- npm-packlist: 5.1.1
- npm-registry-fetch: 14.0.5
- npmlog: 6.0.2
- nx: 16.10.0
+ npm-package-arg: 11.0.2
+ npm-packlist: 8.0.2
+ npm-registry-fetch: 17.1.0
+ nx: 20.8.2
p-map: 4.0.0
p-map-series: 2.1.0
p-queue: 6.6.2
p-reduce: 2.1.0
- pacote: 15.2.0
+ pacote: 18.0.6
pify: 5.0.0
read-cmd-shim: 4.0.0
- read-package-json: 6.0.4
resolve-from: 5.0.0
rimraf: 4.4.1
- semver: 7.6.3
+ semver: 7.7.4
+ set-blocking: 2.0.0
signal-exit: 3.0.7
slash: 3.0.0
- ssri: 9.0.1
- strong-log-transformer: 2.1.0
- tar: 6.1.11
+ ssri: 10.0.6
+ string-width: 4.2.3
+ tar: 6.2.1
temp-dir: 1.0.0
+ through: 2.3.8
+ tinyglobby: 0.2.12
upath: 2.0.1
- uuid: 9.0.1
+ uuid: 10.0.0
validate-npm-package-license: 3.0.4
- validate-npm-package-name: 5.0.0
+ validate-npm-package-name: 5.0.1
+ wide-align: 1.1.5
write-file-atomic: 5.0.1
write-pkg: 4.0.0
- yargs: 16.2.0
- yargs-parser: 20.2.4
+ yargs: 17.7.2
+ yargs-parser: 21.1.1
transitivePeerDependencies:
- '@swc-node/register'
- '@swc/core'
+ - '@types/node'
+ - babel-plugin-macros
- bluebird
- debug
- encoding
- supports-color
- typescript
- '@liuli-util/fs-extra@0.1.0':
- dependencies:
- '@types/fs-extra': 9.0.13
- fs-extra: 10.1.0
-
- '@manypkg/cli@0.21.4':
- dependencies:
- '@manypkg/get-packages': 2.2.2
- chalk: 2.4.2
- detect-indent: 6.1.0
- find-up: 4.1.0
- fs-extra: 8.1.0
- normalize-path: 3.0.0
- p-limit: 2.3.0
- package-json: 8.1.1
- parse-github-url: 1.0.3
- sembear: 0.5.2
- semver: 6.3.1
- spawndamnit: 2.0.0
- validate-npm-package-name: 3.0.0
-
- '@manypkg/find-root@2.2.3':
- dependencies:
- '@manypkg/tools': 1.1.2
-
- '@manypkg/get-packages@2.2.2':
+ '@napi-rs/wasm-runtime@0.2.12':
dependencies:
- '@manypkg/find-root': 2.2.3
- '@manypkg/tools': 1.1.2
+ '@emnapi/core': 1.8.1
+ '@emnapi/runtime': 1.8.1
+ '@tybys/wasm-util': 0.10.1
+ optional: true
- '@manypkg/tools@1.1.2':
+ '@napi-rs/wasm-runtime@0.2.4':
dependencies:
- fast-glob: 3.3.3
- jju: 1.4.0
- js-yaml: 4.1.0
+ '@emnapi/core': 1.8.1
+ '@emnapi/runtime': 1.8.1
+ '@tybys/wasm-util': 0.9.0
'@nodelib/fs.scandir@2.1.5':
dependencies:
@@ -6310,29 +7336,76 @@ snapshots:
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
- fastq: 1.18.0
+ fastq: 1.20.1
'@nolyfill/is-core-module@1.0.39': {}
- '@npmcli/fs@2.1.2':
+ '@npmcli/agent@2.2.2':
+ dependencies:
+ agent-base: 7.1.4
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ lru-cache: 10.4.3
+ socks-proxy-agent: 8.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@npmcli/arborist@7.5.4':
dependencies:
- '@gar/promisify': 1.1.3
- semver: 7.6.3
+ '@isaacs/string-locale-compare': 1.1.0
+ '@npmcli/fs': 3.1.1
+ '@npmcli/installed-package-contents': 2.1.0
+ '@npmcli/map-workspaces': 3.0.6
+ '@npmcli/metavuln-calculator': 7.1.1
+ '@npmcli/name-from-folder': 2.0.0
+ '@npmcli/node-gyp': 3.0.0
+ '@npmcli/package-json': 5.2.0
+ '@npmcli/query': 3.1.0
+ '@npmcli/redact': 2.0.1
+ '@npmcli/run-script': 8.1.0
+ bin-links: 4.0.4
+ cacache: 18.0.4
+ common-ancestor-path: 1.0.1
+ hosted-git-info: 7.0.2
+ json-parse-even-better-errors: 3.0.2
+ json-stringify-nice: 1.1.4
+ lru-cache: 10.4.3
+ minimatch: 9.0.5
+ nopt: 7.2.1
+ npm-install-checks: 6.3.0
+ npm-package-arg: 11.0.2
+ npm-pick-manifest: 9.1.0
+ npm-registry-fetch: 17.1.0
+ pacote: 18.0.6
+ parse-conflict-json: 3.0.1
+ proc-log: 4.2.0
+ proggy: 2.0.0
+ promise-all-reject-late: 1.0.1
+ promise-call-limit: 3.0.2
+ read-package-json-fast: 3.0.2
+ semver: 7.7.4
+ ssri: 10.0.6
+ treeverse: 3.0.0
+ walk-up-path: 3.0.1
+ transitivePeerDependencies:
+ - bluebird
+ - supports-color
'@npmcli/fs@3.1.1':
dependencies:
- semver: 7.6.3
+ semver: 7.7.4
- '@npmcli/git@4.1.0':
+ '@npmcli/git@5.0.8':
dependencies:
- '@npmcli/promise-spawn': 6.0.2
- lru-cache: 7.18.3
- npm-pick-manifest: 8.0.2
- proc-log: 3.0.0
+ '@npmcli/promise-spawn': 7.0.2
+ ini: 4.1.3
+ lru-cache: 10.4.3
+ npm-pick-manifest: 9.1.0
+ proc-log: 4.2.0
promise-inflight: 1.0.1
promise-retry: 2.0.1
- semver: 7.6.3
- which: 3.0.1
+ semver: 7.7.4
+ which: 4.0.0
transitivePeerDependencies:
- bluebird
@@ -6341,383 +7414,332 @@ snapshots:
npm-bundled: 3.0.1
npm-normalize-package-bin: 3.0.1
- '@npmcli/move-file@2.0.1':
- dependencies:
- mkdirp: 1.0.4
- rimraf: 3.0.2
-
- '@npmcli/node-gyp@3.0.0': {}
-
- '@npmcli/promise-spawn@6.0.2':
+ '@npmcli/map-workspaces@3.0.6':
dependencies:
- which: 3.0.1
+ '@npmcli/name-from-folder': 2.0.0
+ glob: 10.5.0
+ minimatch: 9.0.5
+ read-package-json-fast: 3.0.2
- '@npmcli/run-script@6.0.2':
+ '@npmcli/metavuln-calculator@7.1.1':
dependencies:
- '@npmcli/node-gyp': 3.0.0
- '@npmcli/promise-spawn': 6.0.2
- node-gyp: 9.4.1
- read-package-json-fast: 3.0.2
- which: 3.0.1
+ cacache: 18.0.4
+ json-parse-even-better-errors: 3.0.2
+ pacote: 18.0.6
+ proc-log: 4.2.0
+ semver: 7.7.4
transitivePeerDependencies:
- bluebird
- supports-color
- '@nrwl/devkit@16.10.0(nx@16.10.0)':
+ '@npmcli/name-from-folder@2.0.0': {}
+
+ '@npmcli/node-gyp@3.0.0': {}
+
+ '@npmcli/package-json@5.2.0':
dependencies:
- '@nx/devkit': 16.10.0(nx@16.10.0)
+ '@npmcli/git': 5.0.8
+ glob: 10.5.0
+ hosted-git-info: 7.0.2
+ json-parse-even-better-errors: 3.0.2
+ normalize-package-data: 6.0.2
+ proc-log: 4.2.0
+ semver: 7.7.4
transitivePeerDependencies:
- - nx
+ - bluebird
- '@nrwl/tao@16.10.0':
+ '@npmcli/promise-spawn@7.0.2':
dependencies:
- nx: 16.10.0
- tslib: 2.8.1
+ which: 4.0.0
+
+ '@npmcli/query@3.1.0':
+ dependencies:
+ postcss-selector-parser: 6.1.2
+
+ '@npmcli/redact@2.0.1': {}
+
+ '@npmcli/run-script@8.1.0':
+ dependencies:
+ '@npmcli/node-gyp': 3.0.0
+ '@npmcli/package-json': 5.2.0
+ '@npmcli/promise-spawn': 7.0.2
+ node-gyp: 10.3.1
+ proc-log: 4.2.0
+ which: 4.0.0
transitivePeerDependencies:
- - '@swc-node/register'
- - '@swc/core'
- - debug
+ - bluebird
+ - supports-color
- '@nx/devkit@16.10.0(nx@16.10.0)':
+ '@nx/devkit@20.8.2(nx@20.8.2)':
dependencies:
- '@nrwl/devkit': 16.10.0(nx@16.10.0)
ejs: 3.1.10
enquirer: 2.3.6
ignore: 5.3.2
- nx: 16.10.0
- semver: 7.5.3
- tmp: 0.2.3
+ minimatch: 9.0.3
+ nx: 20.8.2
+ semver: 7.7.4
+ tmp: 0.2.5
tslib: 2.8.1
+ yargs-parser: 21.1.1
- '@nx/nx-darwin-arm64@16.10.0':
+ '@nx/nx-darwin-arm64@20.8.2':
optional: true
- '@nx/nx-darwin-x64@16.10.0':
+ '@nx/nx-darwin-x64@20.8.2':
optional: true
- '@nx/nx-freebsd-x64@16.10.0':
+ '@nx/nx-freebsd-x64@20.8.2':
optional: true
- '@nx/nx-linux-arm-gnueabihf@16.10.0':
+ '@nx/nx-linux-arm-gnueabihf@20.8.2':
optional: true
- '@nx/nx-linux-arm64-gnu@16.10.0':
+ '@nx/nx-linux-arm64-gnu@20.8.2':
optional: true
- '@nx/nx-linux-arm64-musl@16.10.0':
+ '@nx/nx-linux-arm64-musl@20.8.2':
optional: true
- '@nx/nx-linux-x64-gnu@16.10.0':
+ '@nx/nx-linux-x64-gnu@20.8.2':
optional: true
- '@nx/nx-linux-x64-musl@16.10.0':
+ '@nx/nx-linux-x64-musl@20.8.2':
optional: true
- '@nx/nx-win32-arm64-msvc@16.10.0':
+ '@nx/nx-win32-arm64-msvc@20.8.2':
optional: true
- '@nx/nx-win32-x64-msvc@16.10.0':
+ '@nx/nx-win32-x64-msvc@20.8.2':
optional: true
- '@octokit/auth-token@3.0.4': {}
+ '@octokit/auth-token@4.0.0': {}
- '@octokit/core@4.2.4(encoding@0.1.13)':
+ '@octokit/core@5.2.2':
dependencies:
- '@octokit/auth-token': 3.0.4
- '@octokit/graphql': 5.0.6(encoding@0.1.13)
- '@octokit/request': 6.2.8(encoding@0.1.13)
- '@octokit/request-error': 3.0.3
- '@octokit/types': 9.3.2
+ '@octokit/auth-token': 4.0.0
+ '@octokit/graphql': 7.1.1
+ '@octokit/request': 8.4.1
+ '@octokit/request-error': 5.1.1
+ '@octokit/types': 13.10.0
before-after-hook: 2.2.3
universal-user-agent: 6.0.1
- transitivePeerDependencies:
- - encoding
- '@octokit/endpoint@7.0.6':
+ '@octokit/endpoint@9.0.6':
dependencies:
- '@octokit/types': 9.3.2
- is-plain-object: 5.0.0
+ '@octokit/types': 13.10.0
universal-user-agent: 6.0.1
- '@octokit/graphql@5.0.6(encoding@0.1.13)':
+ '@octokit/graphql@7.1.1':
dependencies:
- '@octokit/request': 6.2.8(encoding@0.1.13)
- '@octokit/types': 9.3.2
+ '@octokit/request': 8.4.1
+ '@octokit/types': 13.10.0
universal-user-agent: 6.0.1
- transitivePeerDependencies:
- - encoding
- '@octokit/openapi-types@18.1.1': {}
+ '@octokit/openapi-types@24.2.0': {}
'@octokit/plugin-enterprise-rest@6.0.1': {}
- '@octokit/plugin-paginate-rest@6.1.2(@octokit/core@4.2.4(encoding@0.1.13))':
+ '@octokit/plugin-paginate-rest@11.4.4-cjs.2(@octokit/core@5.2.2)':
dependencies:
- '@octokit/core': 4.2.4(encoding@0.1.13)
- '@octokit/tsconfig': 1.0.2
- '@octokit/types': 9.3.2
+ '@octokit/core': 5.2.2
+ '@octokit/types': 13.10.0
- '@octokit/plugin-request-log@1.0.4(@octokit/core@4.2.4(encoding@0.1.13))':
+ '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.2)':
dependencies:
- '@octokit/core': 4.2.4(encoding@0.1.13)
+ '@octokit/core': 5.2.2
- '@octokit/plugin-rest-endpoint-methods@7.2.3(@octokit/core@4.2.4(encoding@0.1.13))':
+ '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1(@octokit/core@5.2.2)':
dependencies:
- '@octokit/core': 4.2.4(encoding@0.1.13)
- '@octokit/types': 10.0.0
+ '@octokit/core': 5.2.2
+ '@octokit/types': 13.10.0
- '@octokit/request-error@3.0.3':
+ '@octokit/request-error@5.1.1':
dependencies:
- '@octokit/types': 9.3.2
+ '@octokit/types': 13.10.0
deprecation: 2.3.1
once: 1.4.0
- '@octokit/request@6.2.8(encoding@0.1.13)':
+ '@octokit/request@8.4.1':
dependencies:
- '@octokit/endpoint': 7.0.6
- '@octokit/request-error': 3.0.3
- '@octokit/types': 9.3.2
- is-plain-object: 5.0.0
- node-fetch: 2.6.7(encoding@0.1.13)
+ '@octokit/endpoint': 9.0.6
+ '@octokit/request-error': 5.1.1
+ '@octokit/types': 13.10.0
universal-user-agent: 6.0.1
- transitivePeerDependencies:
- - encoding
-
- '@octokit/rest@19.0.11(encoding@0.1.13)':
- dependencies:
- '@octokit/core': 4.2.4(encoding@0.1.13)
- '@octokit/plugin-paginate-rest': 6.1.2(@octokit/core@4.2.4(encoding@0.1.13))
- '@octokit/plugin-request-log': 1.0.4(@octokit/core@4.2.4(encoding@0.1.13))
- '@octokit/plugin-rest-endpoint-methods': 7.2.3(@octokit/core@4.2.4(encoding@0.1.13))
- transitivePeerDependencies:
- - encoding
-
- '@octokit/tsconfig@1.0.2': {}
-
- '@octokit/types@10.0.0':
- dependencies:
- '@octokit/openapi-types': 18.1.1
- '@octokit/types@9.3.2':
+ '@octokit/rest@20.1.2':
dependencies:
- '@octokit/openapi-types': 18.1.1
+ '@octokit/core': 5.2.2
+ '@octokit/plugin-paginate-rest': 11.4.4-cjs.2(@octokit/core@5.2.2)
+ '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.2)
+ '@octokit/plugin-rest-endpoint-methods': 13.3.2-cjs.1(@octokit/core@5.2.2)
- '@parcel/watcher@2.0.4':
+ '@octokit/types@13.10.0':
dependencies:
- node-addon-api: 3.2.1
- node-gyp-build: 4.8.4
+ '@octokit/openapi-types': 24.2.0
'@pkgjs/parseargs@0.11.0':
optional: true
- '@pkgr/core@0.1.1': {}
-
- '@pnpm/config.env-replace@1.1.0': {}
+ '@pkgr/core@0.2.9': {}
- '@pnpm/network.ca-file@1.0.2':
+ '@redocly/ajv@8.17.4':
dependencies:
- graceful-fs: 4.2.10
+ fast-deep-equal: 3.1.3
+ fast-uri: 3.1.0
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
- '@pnpm/npm-conf@2.3.1':
- dependencies:
- '@pnpm/config.env-replace': 1.1.0
- '@pnpm/network.ca-file': 1.0.2
- config-chain: 1.1.13
+ '@redocly/config@0.22.2': {}
- '@readme/better-ajv-errors@1.6.0(ajv@8.17.1)':
+ '@redocly/openapi-core@1.34.6':
dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/runtime': 7.26.0
- '@humanwhocodes/momoa': 2.0.4
- ajv: 8.17.1
- chalk: 4.1.2
- json-to-ast: 2.1.0
- jsonpointer: 5.0.1
- leven: 3.1.0
+ '@redocly/ajv': 8.17.4
+ '@redocly/config': 0.22.2
+ colorette: 1.4.0
+ https-proxy-agent: 7.0.6
+ js-levenshtein: 1.1.6
+ js-yaml: 4.1.1
+ minimatch: 5.1.6
+ pluralize: 8.0.0
+ yaml-ast-parser: 0.0.43
+ transitivePeerDependencies:
+ - supports-color
- '@readme/json-schema-ref-parser@1.2.0':
- dependencies:
- '@jsdevtools/ono': 7.1.3
- '@types/json-schema': 7.0.15
- call-me-maybe: 1.0.2
- js-yaml: 4.1.0
+ '@rollup/rollup-android-arm-eabi@4.57.1':
+ optional: true
- '@readme/openapi-parser@2.6.0(openapi-types@12.1.3)':
- dependencies:
- '@apidevtools/swagger-methods': 3.0.2
- '@jsdevtools/ono': 7.1.3
- '@readme/better-ajv-errors': 1.6.0(ajv@8.17.1)
- '@readme/json-schema-ref-parser': 1.2.0
- '@readme/openapi-schemas': 3.1.0
- ajv: 8.17.1
- ajv-draft-04: 1.0.0(ajv@8.17.1)
- call-me-maybe: 1.0.2
- openapi-types: 12.1.3
+ '@rollup/rollup-android-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.57.1':
+ optional: true
- '@readme/openapi-schemas@3.1.0': {}
+ '@rollup/rollup-freebsd-x64@4.57.1':
+ optional: true
- '@rollup/rollup-android-arm-eabi@4.31.0':
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
optional: true
- '@rollup/rollup-android-arm64@4.31.0':
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
optional: true
- '@rollup/rollup-darwin-arm64@4.31.0':
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
optional: true
- '@rollup/rollup-darwin-x64@4.31.0':
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
optional: true
- '@rollup/rollup-freebsd-arm64@4.31.0':
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
optional: true
- '@rollup/rollup-freebsd-x64@4.31.0':
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.31.0':
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.31.0':
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.31.0':
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.31.0':
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
optional: true
- '@rollup/rollup-linux-loongarch64-gnu@4.31.0':
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.31.0':
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.31.0':
+ '@rollup/rollup-linux-x64-musl@4.57.1':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.31.0':
+ '@rollup/rollup-openbsd-x64@4.57.1':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.31.0':
+ '@rollup/rollup-openharmony-arm64@4.57.1':
optional: true
- '@rollup/rollup-linux-x64-musl@4.31.0':
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.31.0':
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.31.0':
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.31.0':
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
optional: true
'@rtsao/scc@1.1.0': {}
- '@sigstore/bundle@1.1.0':
+ '@sigstore/bundle@2.3.2':
dependencies:
- '@sigstore/protobuf-specs': 0.2.1
+ '@sigstore/protobuf-specs': 0.3.3
- '@sigstore/protobuf-specs@0.2.1': {}
+ '@sigstore/core@1.1.0': {}
- '@sigstore/sign@1.0.0':
+ '@sigstore/protobuf-specs@0.3.3': {}
+
+ '@sigstore/sign@2.3.2':
dependencies:
- '@sigstore/bundle': 1.1.0
- '@sigstore/protobuf-specs': 0.2.1
- make-fetch-happen: 11.1.1
+ '@sigstore/bundle': 2.3.2
+ '@sigstore/core': 1.1.0
+ '@sigstore/protobuf-specs': 0.3.3
+ make-fetch-happen: 13.0.1
+ proc-log: 4.2.0
+ promise-retry: 2.0.1
transitivePeerDependencies:
- supports-color
- '@sigstore/tuf@1.0.3':
+ '@sigstore/tuf@2.3.4':
dependencies:
- '@sigstore/protobuf-specs': 0.2.1
- tuf-js: 1.1.7
+ '@sigstore/protobuf-specs': 0.3.3
+ tuf-js: 2.2.1
transitivePeerDependencies:
- supports-color
- '@sinclair/typebox@0.27.8': {}
-
- '@sindresorhus/is@5.6.0': {}
-
- '@sindresorhus/merge-streams@2.3.0': {}
-
- '@sinonjs/commons@3.0.1':
- dependencies:
- type-detect: 4.0.8
-
- '@sinonjs/fake-timers@10.3.0':
+ '@sigstore/verify@1.2.1':
dependencies:
- '@sinonjs/commons': 3.0.1
-
- '@szmarczak/http-timer@5.0.1':
- dependencies:
- defer-to-connect: 2.0.1
-
- '@tootallnate/once@2.0.0': {}
-
- '@ts-rest/core@3.51.0(@types/node@22.10.7)(zod@3.24.1)':
- optionalDependencies:
- '@types/node': 22.10.7
- zod: 3.24.1
-
- '@tsconfig/node10@1.0.11': {}
-
- '@tsconfig/node12@1.0.11': {}
-
- '@tsconfig/node14@1.0.3': {}
+ '@sigstore/bundle': 2.3.2
+ '@sigstore/core': 1.1.0
+ '@sigstore/protobuf-specs': 0.3.3
- '@tsconfig/node16@1.0.4': {}
+ '@sinclair/typebox@0.27.8': {}
- '@tufjs/canonical-json@1.0.0': {}
+ '@tufjs/canonical-json@2.0.0': {}
- '@tufjs/models@1.0.4':
+ '@tufjs/models@2.0.1':
dependencies:
- '@tufjs/canonical-json': 1.0.0
+ '@tufjs/canonical-json': 2.0.0
minimatch: 9.0.5
- '@types/babel__core@7.20.5':
- dependencies:
- '@babel/parser': 7.26.5
- '@babel/types': 7.26.5
- '@types/babel__generator': 7.6.8
- '@types/babel__template': 7.4.4
- '@types/babel__traverse': 7.20.6
-
- '@types/babel__generator@7.6.8':
- dependencies:
- '@babel/types': 7.26.5
-
- '@types/babel__template@7.4.4':
- dependencies:
- '@babel/parser': 7.26.5
- '@babel/types': 7.26.5
-
- '@types/babel__traverse@7.20.6':
+ '@tybys/wasm-util@0.10.1':
dependencies:
- '@babel/types': 7.26.5
-
- '@types/estree@1.0.6': {}
+ tslib: 2.8.1
+ optional: true
- '@types/fs-extra@9.0.13':
+ '@tybys/wasm-util@0.9.0':
dependencies:
- '@types/node': 22.10.7
+ tslib: 2.8.1
- '@types/graceful-fs@4.1.9':
+ '@types/chai@5.2.3':
dependencies:
- '@types/node': 22.10.7
-
- '@types/http-cache-semantics@4.0.4': {}
-
- '@types/istanbul-lib-coverage@2.0.6': {}
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
- '@types/istanbul-lib-report@3.0.3':
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.6
+ '@types/deep-eql@4.0.2': {}
- '@types/istanbul-reports@3.0.4':
- dependencies:
- '@types/istanbul-lib-report': 3.0.3
+ '@types/estree@1.0.8': {}
'@types/json-schema@7.0.15': {}
@@ -6727,38 +7749,28 @@ snapshots:
'@types/minimist@1.2.5': {}
- '@types/node@22.10.7':
+ '@types/node@22.19.11':
dependencies:
- undici-types: 6.20.0
+ undici-types: 6.21.0
'@types/normalize-package-data@2.4.4': {}
- '@types/semver@6.2.7': {}
-
- '@types/semver@7.5.8': {}
-
- '@types/stack-utils@2.0.3': {}
-
- '@types/yargs-parser@21.0.3': {}
-
- '@types/yargs@17.0.33':
- dependencies:
- '@types/yargs-parser': 21.0.3
+ '@types/semver@7.7.1': {}
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)':
dependencies:
- '@eslint-community/regexpp': 4.12.1
+ '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.3)
'@typescript-eslint/scope-manager': 6.21.0
'@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.7.3)
'@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 6.21.0
- debug: 4.4.0
+ debug: 4.4.3
eslint: 8.57.1
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
- semver: 7.6.3
+ semver: 7.7.4
ts-api-utils: 1.4.3(typescript@5.7.3)
optionalDependencies:
typescript: 5.7.3
@@ -6771,7 +7783,7 @@ snapshots:
'@typescript-eslint/types': 6.21.0
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 6.21.0
- debug: 4.4.0
+ debug: 4.4.3
eslint: 8.57.1
optionalDependencies:
typescript: 5.7.3
@@ -6787,7 +7799,7 @@ snapshots:
dependencies:
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.3)
'@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.7.3)
- debug: 4.4.0
+ debug: 4.4.3
eslint: 8.57.1
ts-api-utils: 1.4.3(typescript@5.7.3)
optionalDependencies:
@@ -6795,33 +7807,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/types@5.62.0': {}
-
'@typescript-eslint/types@6.21.0': {}
- '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.3)':
- dependencies:
- '@typescript-eslint/types': 5.62.0
- '@typescript-eslint/visitor-keys': 5.62.0
- debug: 4.4.0
- globby: 11.1.0
- is-glob: 4.0.3
- semver: 7.6.3
- tsutils: 3.21.0(typescript@5.7.3)
- optionalDependencies:
- typescript: 5.7.3
- transitivePeerDependencies:
- - supports-color
-
'@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.3)':
dependencies:
'@typescript-eslint/types': 6.21.0
'@typescript-eslint/visitor-keys': 6.21.0
- debug: 4.4.0
+ debug: 4.4.3
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.3
- semver: 7.6.3
+ semver: 7.7.4
ts-api-utils: 1.4.3(typescript@5.7.3)
optionalDependencies:
typescript: 5.7.3
@@ -6830,195 +7826,181 @@ snapshots:
'@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.7.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
+ '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1)
'@types/json-schema': 7.0.15
- '@types/semver': 7.5.8
+ '@types/semver': 7.7.1
'@typescript-eslint/scope-manager': 6.21.0
'@typescript-eslint/types': 6.21.0
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.3)
eslint: 8.57.1
- semver: 7.6.3
+ semver: 7.7.4
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/visitor-keys@5.62.0':
- dependencies:
- '@typescript-eslint/types': 5.62.0
- eslint-visitor-keys: 3.4.3
-
'@typescript-eslint/visitor-keys@6.21.0':
dependencies:
'@typescript-eslint/types': 6.21.0
eslint-visitor-keys: 3.4.3
- '@typespec/compiler@0.63.0':
- dependencies:
- '@babel/code-frame': 7.25.9
- ajv: 8.17.1
- change-case: 5.4.4
- globby: 14.0.2
- mustache: 4.2.0
- picocolors: 1.1.1
- prettier: 3.3.3
- prompts: 2.4.2
- semver: 7.6.3
- temporal-polyfill: 0.2.5
- vscode-languageserver: 9.0.1
- vscode-languageserver-textdocument: 1.0.12
- yaml: 2.5.1
- yargs: 17.7.2
+ '@ungap/structured-clone@1.3.0': {}
- '@typespec/http@0.63.0(@typespec/compiler@0.63.0)':
- dependencies:
- '@typespec/compiler': 0.63.0
+ '@unrs/resolver-binding-android-arm-eabi@1.11.1':
+ optional: true
- '@typespec/openapi3@0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))(@typespec/openapi@0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0)))(@typespec/versioning@0.63.0(@typespec/compiler@0.63.0))':
- dependencies:
- '@readme/openapi-parser': 2.6.0(openapi-types@12.1.3)
- '@typespec/compiler': 0.63.0
- '@typespec/http': 0.63.0(@typespec/compiler@0.63.0)
- '@typespec/openapi': 0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))
- '@typespec/versioning': 0.63.0(@typespec/compiler@0.63.0)
- openapi-types: 12.1.3
- yaml: 2.5.1
+ '@unrs/resolver-binding-android-arm64@1.11.1':
+ optional: true
- '@typespec/openapi@0.63.0(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))':
- dependencies:
- '@typespec/compiler': 0.63.0
- '@typespec/http': 0.63.0(@typespec/compiler@0.63.0)
+ '@unrs/resolver-binding-darwin-arm64@1.11.1':
+ optional: true
- '@typespec/rest@0.63.1(@typespec/compiler@0.63.0)(@typespec/http@0.63.0(@typespec/compiler@0.63.0))':
- dependencies:
- '@typespec/compiler': 0.63.0
- '@typespec/http': 0.63.0(@typespec/compiler@0.63.0)
+ '@unrs/resolver-binding-darwin-x64@1.11.1':
+ optional: true
- '@typespec/versioning@0.63.0(@typespec/compiler@0.63.0)':
- dependencies:
- '@typespec/compiler': 0.63.0
+ '@unrs/resolver-binding-freebsd-x64@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-arm64-gnu@1.11.1':
+ optional: true
- '@ungap/structured-clone@1.2.1': {}
+ '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-musl@1.11.1':
+ optional: true
- '@vitest/coverage-c8@0.33.0(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))':
+ '@unrs/resolver-binding-wasm32-wasi@1.11.1':
dependencies:
- '@ampproject/remapping': 2.3.0
- c8: 7.14.0
- magic-string: 0.30.17
- picocolors: 1.1.1
- std-env: 3.8.0
- vitest: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ '@napi-rs/wasm-runtime': 0.2.12
+ optional: true
- '@vitest/coverage-v8@3.0.3(vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0))':
+ '@unrs/resolver-binding-win32-arm64-msvc@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-win32-ia32-msvc@1.11.1':
+ optional: true
+
+ '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
+ optional: true
+
+ '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@22.19.11)(yaml@2.8.2))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 1.0.2
- debug: 4.4.0
+ ast-v8-to-istanbul: 0.3.11
+ debug: 4.4.3
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
- istanbul-reports: 3.1.7
- magic-string: 0.30.17
+ istanbul-reports: 3.2.0
+ magic-string: 0.30.21
magicast: 0.3.5
- std-env: 3.8.0
+ std-env: 3.10.0
test-exclude: 7.0.1
tinyrainbow: 2.0.0
- vitest: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ vitest: 3.2.4(@types/node@22.19.11)(yaml@2.8.2)
transitivePeerDependencies:
- supports-color
- '@vitest/expect@3.0.3':
+ '@vitest/expect@3.2.4':
dependencies:
- '@vitest/spy': 3.0.3
- '@vitest/utils': 3.0.3
- chai: 5.1.2
+ '@types/chai': 5.2.3
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.3.3
tinyrainbow: 2.0.0
- '@vitest/mocker@3.0.3(vite@6.0.11(@types/node@22.10.7)(yaml@2.7.0))':
+ '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.11)(yaml@2.8.2))':
dependencies:
- '@vitest/spy': 3.0.3
+ '@vitest/spy': 3.2.4
estree-walker: 3.0.3
- magic-string: 0.30.17
+ magic-string: 0.30.21
optionalDependencies:
- vite: 6.0.11(@types/node@22.10.7)(yaml@2.7.0)
+ vite: 7.3.1(@types/node@22.19.11)(yaml@2.8.2)
- '@vitest/pretty-format@3.0.3':
+ '@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
- '@vitest/runner@3.0.3':
+ '@vitest/runner@3.2.4':
dependencies:
- '@vitest/utils': 3.0.3
- pathe: 2.0.2
+ '@vitest/utils': 3.2.4
+ pathe: 2.0.3
+ strip-literal: 3.1.0
- '@vitest/snapshot@3.0.3':
+ '@vitest/snapshot@3.2.4':
dependencies:
- '@vitest/pretty-format': 3.0.3
- magic-string: 0.30.17
- pathe: 2.0.2
+ '@vitest/pretty-format': 3.2.4
+ magic-string: 0.30.21
+ pathe: 2.0.3
- '@vitest/spy@3.0.3':
+ '@vitest/spy@3.2.4':
dependencies:
- tinyspy: 3.0.2
+ tinyspy: 4.0.4
- '@vitest/utils@3.0.3':
+ '@vitest/utils@3.2.4':
dependencies:
- '@vitest/pretty-format': 3.0.3
- loupe: 3.1.2
+ '@vitest/pretty-format': 3.2.4
+ loupe: 3.2.1
tinyrainbow: 2.0.0
'@yarnpkg/lockfile@1.1.0': {}
- '@yarnpkg/parsers@3.0.0-rc.46':
+ '@yarnpkg/parsers@3.0.2':
dependencies:
- js-yaml: 3.14.1
+ js-yaml: 3.14.2
tslib: 2.8.1
- '@zkochan/js-yaml@0.0.6':
+ '@zkochan/js-yaml@0.0.7':
dependencies:
argparse: 2.0.1
- '@zodios/core@10.9.6(axios@1.7.9)(zod@3.24.1)':
- dependencies:
- axios: 1.7.9
- zod: 3.24.1
-
JSONStream@1.3.5:
dependencies:
jsonparse: 1.3.1
through: 2.3.8
- abbrev@1.1.1: {}
+ abbrev@2.0.0: {}
- acorn-jsx@5.3.2(acorn@8.14.0):
+ acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
- acorn: 8.14.0
+ acorn: 8.15.0
- acorn-walk@8.3.4:
- dependencies:
- acorn: 8.14.0
-
- acorn@8.14.0: {}
+ acorn@8.15.0: {}
add-stream@1.0.0: {}
- agent-base@6.0.2:
- dependencies:
- debug: 4.4.0
- transitivePeerDependencies:
- - supports-color
-
- agentkeepalive@4.6.0:
- dependencies:
- humanize-ms: 1.2.1
+ agent-base@7.1.4: {}
aggregate-error@3.1.0:
dependencies:
clean-stack: 2.2.0
indent-string: 4.0.0
- ajv-draft-04@1.0.0(ajv@8.17.1):
+ ajv-formats@3.0.1(ajv@8.18.0):
optionalDependencies:
- ajv: 8.17.1
+ ajv: 8.18.0
ajv@6.12.6:
dependencies:
@@ -7027,10 +8009,10 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
- ajv@8.17.1:
+ ajv@8.18.0:
dependencies:
fast-deep-equal: 3.1.3
- fast-uri: 3.0.6
+ fast-uri: 3.1.0
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
@@ -7046,11 +8028,7 @@ snapshots:
ansi-regex@5.0.1: {}
- ansi-regex@6.1.0: {}
-
- ansi-styles@3.2.1:
- dependencies:
- color-convert: 1.9.3
+ ansi-regex@6.2.2: {}
ansi-styles@4.3.0:
dependencies:
@@ -7058,26 +8036,10 @@ snapshots:
ansi-styles@5.2.0: {}
- ansi-styles@6.2.1: {}
-
- any-promise@1.3.0: {}
-
- anymatch@3.1.3:
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.1
-
- app-module-path@2.2.0: {}
+ ansi-styles@6.2.3: {}
aproba@2.0.0: {}
- are-we-there-yet@3.0.1:
- dependencies:
- delegates: 1.0.0
- readable-stream: 3.6.2
-
- arg@4.1.3: {}
-
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
@@ -7086,68 +8048,73 @@ snapshots:
array-buffer-byte-length@1.0.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
is-array-buffer: 3.0.5
array-differ@3.0.0: {}
array-ify@1.0.0: {}
- array-includes@3.1.8:
+ array-includes@3.1.9:
dependencies:
call-bind: 1.0.8
+ call-bound: 1.0.4
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-object-atoms: 1.1.1
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
is-string: 1.1.1
+ math-intrinsics: 1.1.0
array-union@2.1.0: {}
- array.prototype.findlastindex@1.2.5:
+ array.prototype.findlastindex@1.2.6:
dependencies:
call-bind: 1.0.8
+ call-bound: 1.0.4
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
- es-shim-unscopables: 1.0.2
+ es-shim-unscopables: 1.1.0
array.prototype.flat@1.3.3:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
- es-shim-unscopables: 1.0.2
+ es-abstract: 1.24.1
+ es-shim-unscopables: 1.1.0
array.prototype.flatmap@1.3.3:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
- es-shim-unscopables: 1.0.2
+ es-abstract: 1.24.1
+ es-shim-unscopables: 1.1.0
arraybuffer.prototype.slice@1.0.4:
dependencies:
array-buffer-byte-length: 1.0.2
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-errors: 1.3.0
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
is-array-buffer: 3.0.5
arrify@1.0.1: {}
arrify@2.0.1: {}
- assert-plus@1.0.0: {}
-
assertion-error@2.0.1: {}
- ast-module-types@5.0.0: {}
+ ast-v8-to-istanbul@0.3.11:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ estree-walker: 3.0.3
+ js-tokens: 10.0.0
- astral-regex@2.0.0: {}
+ async-function@1.0.0: {}
async@3.2.6: {}
@@ -7155,89 +8122,41 @@ snapshots:
available-typed-arrays@1.0.7:
dependencies:
- possible-typed-array-names: 1.0.0
+ possible-typed-array-names: 1.1.0
- axios@1.7.9:
+ axios@1.13.5:
dependencies:
- follow-redirects: 1.15.6
- form-data: 4.0.1
+ follow-redirects: 1.15.11
+ form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
- babel-jest@29.7.0(@babel/core@7.26.0):
- dependencies:
- '@babel/core': 7.26.0
- '@jest/transform': 29.7.0
- '@types/babel__core': 7.20.5
- babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.26.0)
- chalk: 4.1.2
- graceful-fs: 4.2.11
- slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-istanbul@6.1.1:
- dependencies:
- '@babel/helper-plugin-utils': 7.26.5
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-instrument: 5.2.1
- test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-jest-hoist@29.6.3:
- dependencies:
- '@babel/template': 7.25.9
- '@babel/types': 7.26.5
- '@types/babel__core': 7.20.5
- '@types/babel__traverse': 7.20.6
-
- babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0):
- dependencies:
- '@babel/core': 7.26.0
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0)
- '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0)
-
- babel-preset-jest@29.6.3(@babel/core@7.26.0):
- dependencies:
- '@babel/core': 7.26.0
- babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0)
-
balanced-match@1.0.2: {}
base64-js@1.5.1: {}
before-after-hook@2.2.3: {}
+ bin-links@4.0.4:
+ dependencies:
+ cmd-shim: 6.0.3
+ npm-normalize-package-bin: 3.0.1
+ read-cmd-shim: 4.0.0
+ write-file-atomic: 5.0.1
+
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
- brace-expansion@1.1.11:
+ brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
- brace-expansion@2.0.1:
+ brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
@@ -7245,21 +8164,6 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.24.4:
- dependencies:
- caniuse-lite: 1.0.30001695
- electron-to-chromium: 1.5.83
- node-releases: 2.0.19
- update-browserslist-db: 1.1.2(browserslist@4.24.4)
-
- bs-logger@0.2.6:
- dependencies:
- fast-json-stable-stringify: 2.1.0
-
- bser@2.1.1:
- dependencies:
- node-int64: 0.4.0
-
buffer-from@1.1.2: {}
buffer@5.7.1:
@@ -7267,99 +8171,41 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
- builtins@1.0.3: {}
-
- builtins@5.1.0:
- dependencies:
- semver: 7.6.3
-
byte-size@8.1.1: {}
- c8@7.14.0:
- dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@istanbuljs/schema': 0.1.3
- find-up: 5.0.0
- foreground-child: 2.0.0
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-report: 3.0.1
- istanbul-reports: 3.1.7
- rimraf: 3.0.2
- test-exclude: 6.0.0
- v8-to-istanbul: 9.3.0
- yargs: 16.2.0
- yargs-parser: 20.2.9
-
cac@6.7.14: {}
- cacache@16.1.3:
- dependencies:
- '@npmcli/fs': 2.1.2
- '@npmcli/move-file': 2.0.1
- chownr: 2.0.0
- fs-minipass: 2.1.0
- glob: 8.1.0
- infer-owner: 1.0.4
- lru-cache: 7.18.3
- minipass: 3.3.6
- minipass-collect: 1.0.2
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- mkdirp: 1.0.4
- p-map: 4.0.0
- promise-inflight: 1.0.1
- rimraf: 3.0.2
- ssri: 9.0.1
- tar: 6.2.0
- unique-filename: 2.0.1
- transitivePeerDependencies:
- - bluebird
-
- cacache@17.1.4:
+ cacache@18.0.4:
dependencies:
'@npmcli/fs': 3.1.1
fs-minipass: 3.0.3
- glob: 10.4.5
- lru-cache: 7.18.3
+ glob: 10.5.0
+ lru-cache: 10.4.3
minipass: 7.1.2
- minipass-collect: 1.0.2
+ minipass-collect: 2.0.1
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
p-map: 4.0.0
ssri: 10.0.6
- tar: 6.2.0
+ tar: 6.2.1
unique-filename: 3.0.0
- cacheable-lookup@7.0.0: {}
-
- cacheable-request@10.2.14:
- dependencies:
- '@types/http-cache-semantics': 4.0.4
- get-stream: 6.0.1
- http-cache-semantics: 4.1.1
- keyv: 4.5.4
- mimic-response: 4.0.0
- normalize-url: 8.0.1
- responselike: 3.0.0
-
- call-bind-apply-helpers@1.0.1:
+ call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
call-bind@1.0.8:
dependencies:
- call-bind-apply-helpers: 1.0.1
+ call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
set-function-length: 1.2.2
- call-bound@1.0.3:
+ call-bound@1.0.4:
dependencies:
- call-bind-apply-helpers: 1.0.1
- get-intrinsic: 1.2.7
-
- call-me-maybe@1.0.2: {}
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
callsites@3.1.0: {}
@@ -7371,23 +8217,13 @@ snapshots:
camelcase@5.3.1: {}
- camelcase@6.3.0: {}
-
- caniuse-lite@1.0.30001695: {}
-
- chai@5.1.2:
+ chai@5.3.3:
dependencies:
assertion-error: 2.0.1
- check-error: 2.1.1
+ check-error: 2.1.3
deep-eql: 5.0.2
- loupe: 3.1.2
- pathval: 2.0.0
-
- chalk@2.4.2:
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
+ loupe: 3.2.1
+ pathval: 2.0.1
chalk@4.1.0:
dependencies:
@@ -7401,21 +8237,17 @@ snapshots:
chalk@5.3.0: {}
- chalk@5.4.1: {}
+ chalk@5.6.2: {}
- change-case@5.4.4: {}
+ chardet@2.1.1: {}
- char-regex@1.0.2: {}
-
- chardet@0.7.0: {}
-
- check-error@2.1.1: {}
+ check-error@2.1.3: {}
chownr@2.0.0: {}
ci-info@3.9.0: {}
- cjs-module-lexer@1.4.1: {}
+ ci-info@4.4.0: {}
clean-stack@2.2.0: {}
@@ -7464,28 +8296,18 @@ snapshots:
clone@1.0.4: {}
- cmd-shim@6.0.1: {}
-
- co@4.6.0: {}
-
- code-error-fragment@0.0.230: {}
-
- collect-v8-coverage@1.0.2: {}
-
- color-convert@1.9.3:
- dependencies:
- color-name: 1.1.3
+ cmd-shim@6.0.3: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
- color-name@1.1.3: {}
-
color-name@1.1.4: {}
color-support@1.1.3: {}
+ colorette@1.4.0: {}
+
colorette@2.0.20: {}
columnify@1.6.0:
@@ -7497,20 +8319,11 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
- commander@10.0.1: {}
-
commander@11.0.0: {}
commander@12.1.0: {}
- commander@7.2.0: {}
-
- commander@8.3.0: {}
-
- commander@9.5.0:
- optional: true
-
- commondir@1.0.1: {}
+ common-ancestor-path@1.0.1: {}
compare-func@2.0.0:
dependencies:
@@ -7526,11 +8339,6 @@ snapshots:
readable-stream: 3.6.2
typedarray: 0.0.6
- config-chain@1.1.13:
- dependencies:
- ini: 1.3.8
- proto-list: 1.2.4
-
console-control-strings@1.1.0: {}
conventional-changelog-angular@7.0.0:
@@ -7560,7 +8368,7 @@ snapshots:
handlebars: 4.7.8
json-stringify-safe: 5.0.1
meow: 8.1.2
- semver: 7.6.3
+ semver: 7.7.4
split: 1.0.1
conventional-commits-filter@3.0.0:
@@ -7585,72 +8393,42 @@ snapshots:
git-semver-tags: 5.0.1
meow: 8.1.2
- convert-source-map@2.0.0: {}
-
- convict@6.2.4:
- dependencies:
- lodash.clonedeep: 4.5.0
- yargs-parser: 20.2.9
-
core-util-is@1.0.2: {}
- core-util-is@1.0.3: {}
-
- cosmiconfig@8.3.6(typescript@5.7.3):
+ cosmiconfig@9.0.0(typescript@5.7.3):
dependencies:
- import-fresh: 3.3.0
- js-yaml: 4.1.0
+ env-paths: 2.2.1
+ import-fresh: 3.3.1
+ js-yaml: 4.1.1
parse-json: 5.2.0
- path-type: 4.0.0
optionalDependencies:
typescript: 5.7.3
- create-jest@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- create-require@1.1.1: {}
-
- cross-spawn@5.1.0:
- dependencies:
- lru-cache: 4.1.5
- shebang-command: 1.2.0
- which: 1.3.1
-
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
+ cssesc@3.0.0: {}
+
dargs@7.0.0: {}
data-view-buffer@1.0.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
is-data-view: 1.0.2
data-view-byte-length@1.0.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
is-data-view: 1.0.2
data-view-byte-offset@1.0.1:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
is-data-view: 1.0.2
@@ -7664,7 +8442,7 @@ snapshots:
dependencies:
ms: 2.1.2
- debug@4.4.0:
+ debug@4.4.3:
dependencies:
ms: 2.1.3
@@ -7675,28 +8453,16 @@ snapshots:
decamelize@1.2.0: {}
- decompress-response@6.0.0:
- dependencies:
- mimic-response: 3.1.0
-
- dedent@0.7.0: {}
-
dedent@1.5.3: {}
deep-eql@5.0.2: {}
- deep-extend@0.6.0: {}
-
deep-is@0.1.4: {}
- deepmerge@4.3.1: {}
-
defaults@1.0.4:
dependencies:
clone: 1.0.4
- defer-to-connect@2.0.1: {}
-
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.1
@@ -7713,72 +8479,12 @@ snapshots:
delayed-stream@1.0.0: {}
- delegates@1.0.0: {}
-
- dependency-tree@10.0.9:
- dependencies:
- commander: 10.0.1
- filing-cabinet: 4.2.0
- precinct: 11.0.5
- typescript: 5.7.3
- transitivePeerDependencies:
- - supports-color
-
deprecation@2.3.1: {}
detect-indent@5.0.0: {}
- detect-indent@6.1.0: {}
-
- detect-newline@3.1.0: {}
-
- detective-amd@5.0.2:
- dependencies:
- ast-module-types: 5.0.0
- escodegen: 2.1.0
- get-amd-module-type: 5.0.1
- node-source-walk: 6.0.2
-
- detective-cjs@5.0.1:
- dependencies:
- ast-module-types: 5.0.0
- node-source-walk: 6.0.2
-
- detective-es6@4.0.1:
- dependencies:
- node-source-walk: 6.0.2
-
- detective-postcss@6.1.3:
- dependencies:
- is-url: 1.2.4
- postcss: 8.5.1
- postcss-values-parser: 6.0.2(postcss@8.5.1)
-
- detective-sass@5.0.3:
- dependencies:
- gonzales-pe: 4.3.0
- node-source-walk: 6.0.2
-
- detective-scss@4.0.3:
- dependencies:
- gonzales-pe: 4.3.0
- node-source-walk: 6.0.2
-
- detective-stylus@4.0.0: {}
-
- detective-typescript@11.2.0:
- dependencies:
- '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.3)
- ast-module-types: 5.0.0
- node-source-walk: 6.0.2
- typescript: 5.7.3
- transitivePeerDependencies:
- - supports-color
-
diff-sequences@29.6.3: {}
- diff@4.0.2: {}
-
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
@@ -7795,29 +8501,25 @@ snapshots:
dependencies:
is-obj: 2.0.0
- dotenv-expand@10.0.0: {}
+ dotenv-expand@11.0.7:
+ dependencies:
+ dotenv: 16.4.7
- dotenv@16.3.2: {}
+ dotenv@16.4.7: {}
dunder-proto@1.0.1:
dependencies:
- call-bind-apply-helpers: 1.0.1
+ call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
- duplexer@0.1.2: {}
-
eastasianwidth@0.2.0: {}
ejs@3.1.10:
dependencies:
- jake: 10.9.2
+ jake: 10.9.4
- electron-to-chromium@1.5.83: {}
-
- emittery@0.13.1: {}
-
- emoji-regex@10.4.0: {}
+ emoji-regex@10.6.0: {}
emoji-regex@8.0.0: {}
@@ -7828,36 +8530,31 @@ snapshots:
iconv-lite: 0.6.3
optional: true
- end-of-stream@1.4.4:
+ end-of-stream@1.4.5:
dependencies:
once: 1.4.0
- enhanced-resolve@5.18.0:
- dependencies:
- graceful-fs: 4.2.11
- tapable: 2.2.1
-
enquirer@2.3.6:
dependencies:
ansi-colors: 4.1.3
env-paths@2.2.1: {}
- envinfo@7.8.1: {}
+ envinfo@7.13.0: {}
err-code@2.0.3: {}
- error-ex@1.3.2:
+ error-ex@1.3.4:
dependencies:
is-arrayish: 0.2.1
- es-abstract@1.23.9:
+ es-abstract@1.24.1:
dependencies:
array-buffer-byte-length: 1.0.2
arraybuffer.prototype.slice: 1.0.4
available-typed-arrays: 1.0.7
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
data-view-buffer: 1.0.2
data-view-byte-length: 1.0.2
data-view-byte-offset: 1.0.1
@@ -7867,7 +8564,7 @@ snapshots:
es-set-tostringtag: 2.1.0
es-to-primitive: 1.3.0
function.prototype.name: 1.1.8
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
get-proto: 1.0.1
get-symbol-description: 1.1.0
globalthis: 1.0.4
@@ -7880,13 +8577,15 @@ snapshots:
is-array-buffer: 3.0.5
is-callable: 1.2.7
is-data-view: 1.0.2
+ is-negative-zero: 2.0.3
is-regex: 1.2.1
+ is-set: 2.0.3
is-shared-array-buffer: 1.0.4
is-string: 1.1.1
is-typed-array: 1.1.15
- is-weakref: 1.1.0
+ is-weakref: 1.1.1
math-intrinsics: 1.1.0
- object-inspect: 1.13.3
+ object-inspect: 1.13.4
object-keys: 1.1.1
object.assign: 4.1.7
own-keys: 1.0.1
@@ -7895,6 +8594,7 @@ snapshots:
safe-push-apply: 1.0.0
safe-regex-test: 1.1.0
set-proto: 1.0.0
+ stop-iteration-iterator: 1.1.0
string.prototype.trim: 1.2.10
string.prototype.trimend: 1.0.9
string.prototype.trimstart: 1.0.8
@@ -7903,13 +8603,13 @@ snapshots:
typed-array-byte-offset: 1.0.4
typed-array-length: 1.0.7
unbox-primitive: 1.1.0
- which-typed-array: 1.1.18
+ which-typed-array: 1.1.20
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
- es-module-lexer@1.6.0: {}
+ es-module-lexer@1.7.0: {}
es-object-atoms@1.1.1:
dependencies:
@@ -7918,11 +8618,11 @@ snapshots:
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
- es-shim-unscopables@1.0.2:
+ es-shim-unscopables@1.1.0:
dependencies:
hasown: 2.0.2
@@ -7932,51 +8632,42 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
- esbuild@0.24.2:
+ esbuild@0.27.3:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.24.2
- '@esbuild/android-arm': 0.24.2
- '@esbuild/android-arm64': 0.24.2
- '@esbuild/android-x64': 0.24.2
- '@esbuild/darwin-arm64': 0.24.2
- '@esbuild/darwin-x64': 0.24.2
- '@esbuild/freebsd-arm64': 0.24.2
- '@esbuild/freebsd-x64': 0.24.2
- '@esbuild/linux-arm': 0.24.2
- '@esbuild/linux-arm64': 0.24.2
- '@esbuild/linux-ia32': 0.24.2
- '@esbuild/linux-loong64': 0.24.2
- '@esbuild/linux-mips64el': 0.24.2
- '@esbuild/linux-ppc64': 0.24.2
- '@esbuild/linux-riscv64': 0.24.2
- '@esbuild/linux-s390x': 0.24.2
- '@esbuild/linux-x64': 0.24.2
- '@esbuild/netbsd-arm64': 0.24.2
- '@esbuild/netbsd-x64': 0.24.2
- '@esbuild/openbsd-arm64': 0.24.2
- '@esbuild/openbsd-x64': 0.24.2
- '@esbuild/sunos-x64': 0.24.2
- '@esbuild/win32-arm64': 0.24.2
- '@esbuild/win32-ia32': 0.24.2
- '@esbuild/win32-x64': 0.24.2
+ '@esbuild/aix-ppc64': 0.27.3
+ '@esbuild/android-arm': 0.27.3
+ '@esbuild/android-arm64': 0.27.3
+ '@esbuild/android-x64': 0.27.3
+ '@esbuild/darwin-arm64': 0.27.3
+ '@esbuild/darwin-x64': 0.27.3
+ '@esbuild/freebsd-arm64': 0.27.3
+ '@esbuild/freebsd-x64': 0.27.3
+ '@esbuild/linux-arm': 0.27.3
+ '@esbuild/linux-arm64': 0.27.3
+ '@esbuild/linux-ia32': 0.27.3
+ '@esbuild/linux-loong64': 0.27.3
+ '@esbuild/linux-mips64el': 0.27.3
+ '@esbuild/linux-ppc64': 0.27.3
+ '@esbuild/linux-riscv64': 0.27.3
+ '@esbuild/linux-s390x': 0.27.3
+ '@esbuild/linux-x64': 0.27.3
+ '@esbuild/netbsd-arm64': 0.27.3
+ '@esbuild/netbsd-x64': 0.27.3
+ '@esbuild/openbsd-arm64': 0.27.3
+ '@esbuild/openbsd-x64': 0.27.3
+ '@esbuild/openharmony-arm64': 0.27.3
+ '@esbuild/sunos-x64': 0.27.3
+ '@esbuild/win32-arm64': 0.27.3
+ '@esbuild/win32-ia32': 0.27.3
+ '@esbuild/win32-x64': 0.27.3
escalade@3.2.0: {}
escape-string-regexp@1.0.5: {}
- escape-string-regexp@2.0.0: {}
-
escape-string-regexp@4.0.0: {}
- escodegen@2.1.0:
- dependencies:
- esprima: 4.0.1
- estraverse: 5.3.0
- esutils: 2.0.3
- optionalDependencies:
- source-map: 0.6.1
-
- eslint-config-prettier@9.1.0(eslint@8.57.1):
+ eslint-config-prettier@9.1.2(eslint@8.57.1):
dependencies:
eslint: 8.57.1
@@ -7984,49 +8675,48 @@ snapshots:
dependencies:
debug: 3.2.7
is-core-module: 2.16.1
- resolve: 1.22.10
+ resolve: 1.22.11
transitivePeerDependencies:
- supports-color
- eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1):
+ eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1):
dependencies:
'@nolyfill/is-core-module': 1.0.39
- debug: 4.4.0
- enhanced-resolve: 5.18.0
+ debug: 4.4.3
eslint: 8.57.1
- fast-glob: 3.3.3
- get-tsconfig: 4.9.0
- is-bun-module: 1.3.0
- is-glob: 4.0.3
- stable-hash: 0.0.4
+ get-tsconfig: 4.13.6
+ is-bun-module: 2.0.0
+ stable-hash: 0.0.5
+ tinyglobby: 0.2.15
+ unrs-resolver: 1.11.1
optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1)
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1)
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1):
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
- array-includes: 3.1.8
- array.prototype.findlastindex: 1.2.5
+ array-includes: 3.1.9
+ array.prototype.findlastindex: 1.2.6
array.prototype.flat: 1.3.3
array.prototype.flatmap: 1.3.3
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1)
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -8044,14 +8734,14 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2):
+ eslint-plugin-prettier@5.5.5(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.8.1):
dependencies:
eslint: 8.57.1
- prettier: 3.4.2
- prettier-linter-helpers: 1.0.0
- synckit: 0.9.2
+ prettier: 3.8.1
+ prettier-linter-helpers: 1.0.1
+ synckit: 0.11.12
optionalDependencies:
- eslint-config-prettier: 9.1.0(eslint@8.57.1)
+ eslint-config-prettier: 9.1.2(eslint@8.57.1)
eslint-scope@7.2.2:
dependencies:
@@ -8062,24 +8752,24 @@ snapshots:
eslint@8.57.1:
dependencies:
- '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
- '@eslint-community/regexpp': 4.12.1
+ '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1)
+ '@eslint-community/regexpp': 4.12.2
'@eslint/eslintrc': 2.1.4
'@eslint/js': 8.57.1
'@humanwhocodes/config-array': 0.13.0
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
- '@ungap/structured-clone': 1.2.1
+ '@ungap/structured-clone': 1.3.0
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
- debug: 4.4.0
+ debug: 4.4.3
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
- esquery: 1.6.0
+ esquery: 1.7.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
@@ -8091,7 +8781,7 @@ snapshots:
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
@@ -8105,13 +8795,13 @@ snapshots:
espree@9.6.1:
dependencies:
- acorn: 8.14.0
- acorn-jsx: 5.3.2(acorn@8.14.0)
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 3.4.3
esprima@4.0.1: {}
- esquery@1.6.0:
+ esquery@1.7.0:
dependencies:
estraverse: 5.3.0
@@ -8123,34 +8813,20 @@ snapshots:
estree-walker@3.0.3:
dependencies:
- '@types/estree': 1.0.6
+ '@types/estree': 1.0.8
esutils@2.0.3: {}
- eval-estree-expression@2.0.3: {}
-
eventemitter3@4.0.7: {}
- eventemitter3@5.0.1: {}
+ eventemitter3@5.0.4: {}
execa@5.0.0:
- dependencies:
- cross-spawn: 7.0.6
- get-stream: 6.0.0
- human-signals: 2.1.0
- is-stream: 2.0.0
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
-
- execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
get-stream: 6.0.1
human-signals: 2.1.0
- is-stream: 2.0.1
+ is-stream: 2.0.0
merge-stream: 2.0.0
npm-run-path: 4.0.1
onetime: 5.1.2
@@ -8169,27 +8845,9 @@ snapshots:
signal-exit: 3.0.7
strip-final-newline: 3.0.0
- exit@0.1.2: {}
-
- expect-type@1.1.0: {}
-
- expect@29.7.0:
- dependencies:
- '@jest/expect-utils': 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
-
- exponential-backoff@3.1.1: {}
-
- external-editor@3.1.0:
- dependencies:
- chardet: 0.7.0
- iconv-lite: 0.4.24
- tmp: 0.0.33
+ expect-type@1.3.0: {}
- extsprintf@1.4.1: {}
+ exponential-backoff@3.1.3: {}
fast-deep-equal@3.1.3: {}
@@ -8207,15 +8865,15 @@ snapshots:
fast-levenshtein@2.0.6: {}
- fast-uri@3.0.6: {}
+ fast-uri@3.1.0: {}
- fastq@1.18.0:
+ fastq@1.20.1:
dependencies:
- reusify: 1.0.4
+ reusify: 1.1.0
- fb-watchman@2.0.2:
- dependencies:
- bser: 2.1.1
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
figures@3.2.0:
dependencies:
@@ -8226,23 +8884,8 @@ snapshots:
flat-cache: 3.2.0
filelist@1.0.4:
- dependencies:
- minimatch: 5.1.6
-
- filing-cabinet@4.2.0:
- dependencies:
- app-module-path: 2.2.0
- commander: 10.0.1
- enhanced-resolve: 5.18.0
- is-relative-path: 1.0.2
- module-definition: 5.0.1
- module-lookup-amd: 8.0.5
- resolve: 1.22.10
- resolve-dependency-path: 3.0.2
- sass-lookup: 5.0.1
- stylus-lookup: 5.0.1
- tsconfig-paths: 4.2.0
- typescript: 5.7.3
+ dependencies:
+ minimatch: 5.1.6
fill-range@7.1.1:
dependencies:
@@ -8264,57 +8907,44 @@ snapshots:
flat-cache@3.2.0:
dependencies:
- flatted: 3.3.2
+ flatted: 3.3.3
keyv: 4.5.4
rimraf: 3.0.2
flat@5.0.2: {}
- flatted@3.3.2: {}
+ flatted@3.3.3: {}
- follow-redirects@1.15.6: {}
+ follow-redirects@1.15.11: {}
- for-each@0.3.3:
+ for-each@0.3.5:
dependencies:
is-callable: 1.2.7
- foreground-child@2.0.0:
- dependencies:
- cross-spawn: 7.0.6
- signal-exit: 3.0.7
-
- foreground-child@3.3.0:
+ foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- form-data-encoder@2.1.4: {}
-
- form-data@4.0.1:
+ form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
mime-types: 2.1.35
- fs-constants@1.0.0: {}
-
- fs-extra@10.1.0:
+ front-matter@4.0.2:
dependencies:
- graceful-fs: 4.2.11
- jsonfile: 6.1.0
- universalify: 2.0.1
+ js-yaml: 3.14.2
- fs-extra@11.3.0:
- dependencies:
- graceful-fs: 4.2.11
- jsonfile: 6.1.0
- universalify: 2.0.1
+ fs-constants@1.0.0: {}
- fs-extra@8.1.0:
+ fs-extra@11.3.3:
dependencies:
graceful-fs: 4.2.11
- jsonfile: 4.0.0
- universalify: 0.1.2
+ jsonfile: 6.2.0
+ universalify: 2.0.1
fs-minipass@2.1.0:
dependencies:
@@ -8334,7 +8964,7 @@ snapshots:
function.prototype.name@1.1.8:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
define-properties: 1.2.1
functions-have-names: 1.2.3
hasown: 2.0.2
@@ -8342,31 +8972,15 @@ snapshots:
functions-have-names@1.2.3: {}
- gauge@4.0.4:
- dependencies:
- aproba: 2.0.0
- color-support: 1.1.3
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- signal-exit: 3.0.7
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wide-align: 1.1.5
-
- gensync@1.0.0-beta.2: {}
-
- get-amd-module-type@5.0.1:
- dependencies:
- ast-module-types: 5.0.0
- node-source-walk: 6.0.2
+ generator-function@2.0.1: {}
get-caller-file@2.0.5: {}
- get-east-asian-width@1.3.0: {}
+ get-east-asian-width@1.4.0: {}
- get-intrinsic@1.2.7:
+ get-intrinsic@1.3.0:
dependencies:
- call-bind-apply-helpers: 1.0.1
+ call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
@@ -8377,10 +8991,6 @@ snapshots:
hasown: 2.0.2
math-intrinsics: 1.1.0
- get-own-enumerable-property-symbols@3.0.2: {}
-
- get-package-type@0.1.0: {}
-
get-pkg-repo@4.2.1:
dependencies:
'@hutson/parse-repository-url': 3.0.2
@@ -8401,11 +9011,11 @@ snapshots:
get-symbol-description@1.1.0:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
- get-tsconfig@4.9.0:
+ get-tsconfig@4.13.6:
dependencies:
resolve-pkg-maps: 1.0.0
@@ -8423,14 +9033,14 @@ snapshots:
git-semver-tags@5.0.1:
dependencies:
meow: 8.1.2
- semver: 7.6.3
+ semver: 7.7.4
git-up@7.0.0:
dependencies:
- is-ssh: 1.4.0
+ is-ssh: 1.4.1
parse-url: 8.1.0
- git-url-parse@13.1.0:
+ git-url-parse@14.0.0:
dependencies:
git-up: 7.0.0
@@ -8446,24 +9056,15 @@ snapshots:
dependencies:
is-glob: 4.0.3
- glob@10.4.5:
+ glob@10.5.0:
dependencies:
- foreground-child: 3.3.0
+ foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
- glob@7.1.4:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.0.5
- once: 1.4.0
- path-is-absolute: 1.0.1
-
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -8473,14 +9074,6 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
- glob@8.1.0:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 5.1.6
- once: 1.4.0
-
glob@9.3.5:
dependencies:
fs.realpath: 1.0.0
@@ -8488,8 +9081,6 @@ snapshots:
minipass: 4.2.8
path-scurry: 1.11.1
- globals@11.12.0: {}
-
globals@13.24.0:
dependencies:
type-fest: 0.20.2
@@ -8508,41 +9099,10 @@ snapshots:
merge2: 1.4.1
slash: 3.0.0
- globby@14.0.2:
- dependencies:
- '@sindresorhus/merge-streams': 2.3.0
- fast-glob: 3.3.3
- ignore: 5.3.2
- path-type: 5.0.0
- slash: 5.1.0
- unicorn-magic: 0.1.0
-
- gonzales-pe@4.3.0:
- dependencies:
- minimist: 1.2.8
-
gopd@1.2.0: {}
- got@12.6.1:
- dependencies:
- '@sindresorhus/is': 5.6.0
- '@szmarczak/http-timer': 5.0.1
- cacheable-lookup: 7.0.0
- cacheable-request: 10.2.14
- decompress-response: 6.0.0
- form-data-encoder: 2.1.4
- get-stream: 6.0.1
- http2-wrapper: 2.2.1
- lowercase-keys: 3.0.0
- p-cancelable: 3.0.0
- responselike: 3.0.0
-
- graceful-fs@4.2.10: {}
-
graceful-fs@4.2.11: {}
- grapheme-splitter@1.0.4: {}
-
graphemer@1.4.0: {}
handlebars@4.7.8:
@@ -8558,8 +9118,6 @@ snapshots:
has-bigints@1.1.0: {}
- has-flag@3.0.0: {}
-
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
@@ -8584,39 +9142,29 @@ snapshots:
hosted-git-info@2.8.9: {}
- hosted-git-info@3.0.8:
- dependencies:
- lru-cache: 6.0.0
-
hosted-git-info@4.1.0:
dependencies:
lru-cache: 6.0.0
- hosted-git-info@6.1.3:
+ hosted-git-info@7.0.2:
dependencies:
- lru-cache: 7.18.3
+ lru-cache: 10.4.3
html-escaper@2.0.2: {}
- http-cache-semantics@4.1.1: {}
+ http-cache-semantics@4.2.0: {}
- http-proxy-agent@5.0.0:
+ http-proxy-agent@7.0.2:
dependencies:
- '@tootallnate/once': 2.0.0
- agent-base: 6.0.2
- debug: 4.4.0
+ agent-base: 7.1.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
- http2-wrapper@2.2.1:
- dependencies:
- quick-lru: 5.1.1
- resolve-alpn: 1.2.1
-
- https-proxy-agent@5.0.1:
+ https-proxy-agent@7.0.6:
dependencies:
- agent-base: 6.0.2
- debug: 4.4.0
+ agent-base: 7.1.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
@@ -8624,34 +9172,26 @@ snapshots:
human-signals@4.3.1: {}
- humanize-ms@1.2.1:
- dependencies:
- ms: 2.1.3
-
husky@8.0.3: {}
- iconv-lite@0.4.24:
+ iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
+ optional: true
- iconv-lite@0.6.3:
+ iconv-lite@0.7.2:
dependencies:
safer-buffer: 2.1.2
- optional: true
ieee754@1.2.1: {}
- ignore-walk@5.0.1:
- dependencies:
- minimatch: 5.1.6
-
ignore-walk@6.0.5:
dependencies:
minimatch: 9.0.5
ignore@5.3.2: {}
- import-fresh@3.3.0:
+ import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
@@ -8661,17 +9201,10 @@ snapshots:
pkg-dir: 4.2.0
resolve-cwd: 3.0.0
- import-local@3.2.0:
- dependencies:
- pkg-dir: 4.2.0
- resolve-cwd: 3.0.0
-
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
- infer-owner@1.0.4: {}
-
inflight@1.0.6:
dependencies:
once: 1.4.0
@@ -8681,44 +9214,39 @@ snapshots:
ini@1.3.8: {}
- init-package-json@5.0.0:
+ ini@4.1.3: {}
+
+ init-package-json@6.0.3:
dependencies:
- npm-package-arg: 10.1.0
+ '@npmcli/package-json': 5.2.0
+ npm-package-arg: 11.0.2
promzard: 1.0.2
- read: 2.1.0
- read-package-json: 6.0.4
- semver: 7.6.3
+ read: 3.0.1
+ semver: 7.7.4
validate-npm-package-license: 3.0.4
- validate-npm-package-name: 5.0.0
-
- inquirer@12.3.2(@types/node@22.10.7):
- dependencies:
- '@inquirer/core': 10.1.4(@types/node@22.10.7)
- '@inquirer/prompts': 7.2.3(@types/node@22.10.7)
- '@inquirer/type': 3.0.2(@types/node@22.10.7)
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
- mute-stream: 2.0.0
- run-async: 3.0.0
- rxjs: 7.8.1
+ validate-npm-package-name: 5.0.1
+ transitivePeerDependencies:
+ - bluebird
- inquirer@8.2.6:
+ inquirer@8.2.7(@types/node@22.19.11):
dependencies:
+ '@inquirer/external-editor': 1.0.3(@types/node@22.19.11)
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-cursor: 3.1.0
cli-width: 3.0.0
- external-editor: 3.1.0
figures: 3.2.0
- lodash: 4.17.21
+ lodash: 4.17.23
mute-stream: 0.0.8
ora: 5.4.1
run-async: 2.4.1
- rxjs: 7.8.1
+ rxjs: 7.8.2
string-width: 4.2.3
strip-ansi: 6.0.1
through: 2.3.8
wrap-ansi: 6.2.0
+ transitivePeerDependencies:
+ - '@types/node'
internal-slot@1.1.0:
dependencies:
@@ -8726,24 +9254,20 @@ snapshots:
hasown: 2.0.2
side-channel: 1.1.0
- ip-address@9.0.5:
- dependencies:
- jsbn: 1.1.0
- sprintf-js: 1.1.3
-
- ip@2.0.1: {}
+ ip-address@10.1.0: {}
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
- get-intrinsic: 1.2.7
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
is-arrayish@0.2.1: {}
- is-async-function@2.1.0:
+ is-async-function@2.1.1:
dependencies:
- call-bound: 1.0.3
+ async-function: 1.0.0
+ call-bound: 1.0.4
get-proto: 1.0.1
has-tostringtag: 1.0.2
safe-regex-test: 1.1.0
@@ -8752,14 +9276,14 @@ snapshots:
dependencies:
has-bigints: 1.1.0
- is-boolean-object@1.2.1:
+ is-boolean-object@1.2.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
has-tostringtag: 1.0.2
- is-bun-module@1.3.0:
+ is-bun-module@2.0.0:
dependencies:
- semver: 7.6.3
+ semver: 7.7.4
is-callable@1.2.7: {}
@@ -8773,13 +9297,13 @@ snapshots:
is-data-view@1.0.2:
dependencies:
- call-bound: 1.0.3
- get-intrinsic: 1.2.7
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
is-typed-array: 1.1.15
is-date-object@1.1.0:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
has-tostringtag: 1.0.2
is-docker@2.2.1: {}
@@ -8788,17 +9312,16 @@ snapshots:
is-finalizationregistry@1.1.1:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
is-fullwidth-code-point@3.0.0: {}
is-fullwidth-code-point@4.0.0: {}
- is-generator-fn@2.1.0: {}
-
- is-generator-function@1.1.0:
+ is-generator-function@1.1.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
+ generator-function: 2.0.1
get-proto: 1.0.1
has-tostringtag: 1.0.2
safe-regex-test: 1.1.0
@@ -8815,482 +9338,147 @@ snapshots:
is-map@2.0.3: {}
+ is-negative-zero@2.0.3: {}
+
is-number-object@1.1.1:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
has-tostringtag: 1.0.2
is-number@7.0.0: {}
- is-obj@1.0.1: {}
-
- is-obj@2.0.0: {}
-
- is-path-inside@3.0.3: {}
-
- is-plain-obj@1.1.0: {}
-
- is-plain-object@2.0.4:
- dependencies:
- isobject: 3.0.1
-
- is-plain-object@5.0.0: {}
-
- is-regex@1.2.1:
- dependencies:
- call-bound: 1.0.3
- gopd: 1.2.0
- has-tostringtag: 1.0.2
- hasown: 2.0.2
-
- is-regexp@1.0.0: {}
-
- is-relative-path@1.0.2: {}
-
- is-set@2.0.3: {}
-
- is-shared-array-buffer@1.0.4:
- dependencies:
- call-bound: 1.0.3
-
- is-ssh@1.4.0:
- dependencies:
- protocols: 2.0.1
-
- is-stream@2.0.0: {}
-
- is-stream@2.0.1: {}
-
- is-stream@3.0.0: {}
-
- is-string@1.1.1:
- dependencies:
- call-bound: 1.0.3
- has-tostringtag: 1.0.2
-
- is-symbol@1.1.1:
- dependencies:
- call-bound: 1.0.3
- has-symbols: 1.1.0
- safe-regex-test: 1.1.0
-
- is-text-path@1.0.1:
- dependencies:
- text-extensions: 1.9.0
-
- is-typed-array@1.1.15:
- dependencies:
- which-typed-array: 1.1.18
-
- is-unicode-supported@0.1.0: {}
-
- is-unicode-supported@1.3.0: {}
-
- is-unicode-supported@2.1.0: {}
-
- is-url-superb@4.0.0: {}
-
- is-url@1.2.4: {}
-
- is-weakmap@2.0.2: {}
-
- is-weakref@1.1.0:
- dependencies:
- call-bound: 1.0.3
-
- is-weakset@2.0.4:
- dependencies:
- call-bound: 1.0.3
- get-intrinsic: 1.2.7
-
- is-wsl@2.2.0:
- dependencies:
- is-docker: 2.2.1
-
- isarray@1.0.0: {}
-
- isarray@2.0.5: {}
-
- isexe@2.0.0: {}
-
- isobject@3.0.1: {}
-
- istanbul-lib-coverage@3.2.2: {}
-
- istanbul-lib-instrument@5.2.1:
- dependencies:
- '@babel/core': 7.26.0
- '@babel/parser': 7.26.5
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-instrument@6.0.3:
- dependencies:
- '@babel/core': 7.26.0
- '@babel/parser': 7.26.5
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 7.6.3
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-report@3.0.1:
- dependencies:
- istanbul-lib-coverage: 3.2.2
- make-dir: 4.0.0
- supports-color: 7.2.0
-
- istanbul-lib-source-maps@4.0.1:
- dependencies:
- debug: 4.4.0
- istanbul-lib-coverage: 3.2.2
- source-map: 0.6.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-source-maps@5.0.6:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- debug: 4.4.0
- istanbul-lib-coverage: 3.2.2
- transitivePeerDependencies:
- - supports-color
-
- istanbul-reports@3.1.7:
- dependencies:
- html-escaper: 2.0.2
- istanbul-lib-report: 3.0.1
-
- jackspeak@3.4.3:
- dependencies:
- '@isaacs/cliui': 8.0.2
- optionalDependencies:
- '@pkgjs/parseargs': 0.11.0
-
- jake@10.9.2:
- dependencies:
- async: 3.2.6
- chalk: 4.1.2
- filelist: 1.0.4
- minimatch: 3.1.2
-
- jest-changed-files@29.7.0:
- dependencies:
- execa: 5.1.1
- jest-util: 29.7.0
- p-limit: 3.1.0
-
- jest-circus@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- chalk: 4.1.2
- co: 4.6.0
- dedent: 1.5.3
- is-generator-fn: 2.1.0
- jest-each: 29.7.0
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- p-limit: 3.1.0
- pretty-format: 29.7.0
- pure-rand: 6.1.0
- slash: 3.0.0
- stack-utils: 2.0.6
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-cli@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- jest-config@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)):
- dependencies:
- '@babel/core': 7.26.0
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.26.0)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 22.10.7
- ts-node: 10.9.2(@types/node@22.10.7)(typescript@5.7.3)
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-diff@29.7.0:
+ is-obj@2.0.0: {}
+
+ is-path-inside@3.0.3: {}
+
+ is-plain-obj@1.1.0: {}
+
+ is-plain-object@2.0.4:
dependencies:
- chalk: 4.1.2
- diff-sequences: 29.6.3
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ isobject: 3.0.1
- jest-docblock@29.7.0:
+ is-regex@1.2.1:
dependencies:
- detect-newline: 3.1.0
+ call-bound: 1.0.4
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ is-set@2.0.3: {}
- jest-each@29.7.0:
+ is-shared-array-buffer@1.0.4:
dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- jest-get-type: 29.6.3
- jest-util: 29.7.0
- pretty-format: 29.7.0
+ call-bound: 1.0.4
- jest-environment-node@29.7.0:
+ is-ssh@1.4.1:
dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- jest-mock: 29.7.0
- jest-util: 29.7.0
+ protocols: 2.0.2
- jest-get-type@29.6.3: {}
+ is-stream@2.0.0: {}
- jest-haste-map@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/graceful-fs': 4.1.9
- '@types/node': 22.10.7
- anymatch: 3.1.3
- fb-watchman: 2.0.2
- graceful-fs: 4.2.11
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- jest-worker: 29.7.0
- micromatch: 4.0.8
- walker: 1.0.8
- optionalDependencies:
- fsevents: 2.3.3
+ is-stream@3.0.0: {}
- jest-leak-detector@29.7.0:
+ is-string@1.1.1:
dependencies:
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- jest-matcher-utils@29.7.0:
+ is-symbol@1.1.1:
dependencies:
- chalk: 4.1.2
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
+ call-bound: 1.0.4
+ has-symbols: 1.1.0
+ safe-regex-test: 1.1.0
- jest-message-util@29.7.0:
+ is-text-path@1.0.1:
dependencies:
- '@babel/code-frame': 7.26.2
- '@jest/types': 29.6.3
- '@types/stack-utils': 2.0.3
- chalk: 4.1.2
- graceful-fs: 4.2.11
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- stack-utils: 2.0.6
+ text-extensions: 1.9.0
- jest-mock@29.7.0:
+ is-typed-array@1.1.15:
dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- jest-util: 29.7.0
+ which-typed-array: 1.1.20
- jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
- optionalDependencies:
- jest-resolve: 29.7.0
+ is-unicode-supported@0.1.0: {}
+
+ is-unicode-supported@1.3.0: {}
+
+ is-unicode-supported@2.1.0: {}
- jest-regex-util@29.6.3: {}
+ is-weakmap@2.0.2: {}
- jest-resolve-dependencies@29.7.0:
+ is-weakref@1.1.1:
dependencies:
- jest-regex-util: 29.6.3
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
+ call-bound: 1.0.4
- jest-resolve@29.7.0:
+ is-weakset@2.0.4:
dependencies:
- chalk: 4.1.2
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- resolve: 1.22.10
- resolve.exports: 2.0.3
- slash: 3.0.0
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
- jest-runner@29.7.0:
+ is-wsl@2.2.0:
dependencies:
- '@jest/console': 29.7.0
- '@jest/environment': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- chalk: 4.1.2
- emittery: 0.13.1
- graceful-fs: 4.2.11
- jest-docblock: 29.7.0
- jest-environment-node: 29.7.0
- jest-haste-map: 29.7.0
- jest-leak-detector: 29.7.0
- jest-message-util: 29.7.0
- jest-resolve: 29.7.0
- jest-runtime: 29.7.0
- jest-util: 29.7.0
- jest-watcher: 29.7.0
- jest-worker: 29.7.0
- p-limit: 3.1.0
- source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
+ is-docker: 2.2.1
+
+ isarray@1.0.0: {}
+
+ isarray@2.0.5: {}
+
+ isexe@2.0.0: {}
+
+ isexe@3.1.5: {}
+
+ isobject@3.0.1: {}
- jest-runtime@29.7.0:
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-report@3.0.1:
dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/globals': 29.7.0
- '@jest/source-map': 29.6.3
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- chalk: 4.1.2
- cjs-module-lexer: 1.4.1
- collect-v8-coverage: 1.0.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
- strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
- jest-snapshot@29.7.0:
- dependencies:
- '@babel/core': 7.26.0
- '@babel/generator': 7.26.5
- '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0)
- '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0)
- '@babel/types': 7.26.5
- '@jest/expect-utils': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0)
- chalk: 4.1.2
- expect: 29.7.0
- graceful-fs: 4.2.11
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- natural-compare: 1.4.0
- pretty-format: 29.7.0
- semver: 7.6.3
+ istanbul-lib-source-maps@5.0.6:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ debug: 4.4.3
+ istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
- supports-color
- jest-util@29.7.0:
+ istanbul-reports@3.2.0:
dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- chalk: 4.1.2
- ci-info: 3.9.0
- graceful-fs: 4.2.11
- picomatch: 2.3.1
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
- jest-validate@29.7.0:
+ jackspeak@3.4.3:
dependencies:
- '@jest/types': 29.6.3
- camelcase: 6.3.0
- chalk: 4.1.2
- jest-get-type: 29.6.3
- leven: 3.1.0
- pretty-format: 29.7.0
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
- jest-watcher@29.7.0:
+ jake@10.9.4:
dependencies:
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.10.7
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- emittery: 0.13.1
- jest-util: 29.7.0
- string-length: 4.0.2
+ async: 3.2.6
+ filelist: 1.0.4
+ picocolors: 1.1.1
- jest-worker@29.7.0:
+ jest-diff@29.7.0:
dependencies:
- '@types/node': 22.10.7
- jest-util: 29.7.0
- merge-stream: 2.0.0
- supports-color: 8.1.1
+ chalk: 4.1.2
+ diff-sequences: 29.6.3
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
- jest@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
+ jest-get-type@29.6.3: {}
- jju@1.4.0: {}
+ js-levenshtein@1.1.6: {}
+
+ js-tokens@10.0.0: {}
js-tokens@4.0.0: {}
- js-yaml@3.14.1:
+ js-tokens@9.0.1: {}
+
+ js-yaml@3.14.2:
dependencies:
argparse: 1.0.10
esprima: 4.0.1
@@ -9299,9 +9487,9 @@ snapshots:
dependencies:
argparse: 2.0.1
- jsbn@1.1.0: {}
-
- jsesc@3.1.0: {}
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
json-buffer@3.0.1: {}
@@ -9311,34 +9499,17 @@ snapshots:
json-parse-even-better-errors@3.0.2: {}
- json-schema-diff@0.18.1:
- dependencies:
- ajv: 8.17.1
- commander: 10.0.1
- convict: 6.2.4
- json-schema-ref-parser: 9.0.9
- json-schema-spec-types: 0.1.2
- lodash: 4.17.21
- verror: 1.10.1
-
- json-schema-ref-parser@9.0.9:
- dependencies:
- '@apidevtools/json-schema-ref-parser': 9.0.9
-
- json-schema-spec-types@0.1.2: {}
-
json-schema-traverse@0.4.1: {}
json-schema-traverse@1.0.0: {}
+ json-schema-typed@8.0.2: {}
+
json-stable-stringify-without-jsonify@1.0.1: {}
- json-stringify-safe@5.0.1: {}
+ json-stringify-nice@1.1.4: {}
- json-to-ast@2.1.0:
- dependencies:
- code-error-fragment: 0.0.230
- grapheme-splitter: 1.0.4
+ json-stringify-safe@5.0.1: {}
json5@1.0.2:
dependencies:
@@ -9348,11 +9519,7 @@ snapshots:
jsonc-parser@3.2.0: {}
- jsonfile@4.0.0:
- optionalDependencies:
- graceful-fs: 4.2.11
-
- jsonfile@6.1.0:
+ jsonfile@6.2.0:
dependencies:
universalify: 2.0.1
optionalDependencies:
@@ -9360,7 +9527,9 @@ snapshots:
jsonparse@1.3.1: {}
- jsonpointer@5.0.1: {}
+ just-diff-apply@5.5.0: {}
+
+ just-diff@6.0.2: {}
keyv@4.5.4:
dependencies:
@@ -9368,116 +9537,118 @@ snapshots:
kind-of@6.0.3: {}
- kleur@3.0.3: {}
-
- lerna@7.4.2(encoding@0.1.13):
+ lerna@8.2.4(@types/node@22.19.11)(encoding@0.1.13):
dependencies:
- '@lerna/child-process': 7.4.2
- '@lerna/create': 7.4.2(encoding@0.1.13)(typescript@5.7.3)
- '@npmcli/run-script': 6.0.2
- '@nx/devkit': 16.10.0(nx@16.10.0)
+ '@lerna/create': 8.2.4(@types/node@22.19.11)(encoding@0.1.13)(typescript@5.7.3)
+ '@npmcli/arborist': 7.5.4
+ '@npmcli/package-json': 5.2.0
+ '@npmcli/run-script': 8.1.0
+ '@nx/devkit': 20.8.2(nx@20.8.2)
'@octokit/plugin-enterprise-rest': 6.0.1
- '@octokit/rest': 19.0.11(encoding@0.1.13)
+ '@octokit/rest': 20.1.2
+ aproba: 2.0.0
byte-size: 8.1.1
chalk: 4.1.0
clone-deep: 4.0.1
- cmd-shim: 6.0.1
+ cmd-shim: 6.0.3
+ color-support: 1.1.3
columnify: 1.6.0
+ console-control-strings: 1.1.0
conventional-changelog-angular: 7.0.0
conventional-changelog-core: 5.0.1
conventional-recommended-bump: 7.0.1
- cosmiconfig: 8.3.6(typescript@5.7.3)
- dedent: 0.7.0
- envinfo: 7.8.1
+ cosmiconfig: 9.0.0(typescript@5.7.3)
+ dedent: 1.5.3
+ envinfo: 7.13.0
execa: 5.0.0
- fs-extra: 11.3.0
+ fs-extra: 11.3.3
get-port: 5.1.1
get-stream: 6.0.0
- git-url-parse: 13.1.0
- glob-parent: 5.1.2
- globby: 11.1.0
+ git-url-parse: 14.0.0
+ glob-parent: 6.0.2
graceful-fs: 4.2.11
has-unicode: 2.0.1
import-local: 3.1.0
ini: 1.3.8
- init-package-json: 5.0.0
- inquirer: 8.2.6
+ init-package-json: 6.0.3
+ inquirer: 8.2.7(@types/node@22.19.11)
is-ci: 3.0.1
is-stream: 2.0.0
jest-diff: 29.7.0
js-yaml: 4.1.0
- libnpmaccess: 7.0.2
- libnpmpublish: 7.3.0
+ libnpmaccess: 8.0.6
+ libnpmpublish: 9.0.9
load-json-file: 6.2.0
- lodash: 4.17.21
make-dir: 4.0.0
minimatch: 3.0.5
multimatch: 5.0.0
node-fetch: 2.6.7(encoding@0.1.13)
- npm-package-arg: 8.1.1
- npm-packlist: 5.1.1
- npm-registry-fetch: 14.0.5
- npmlog: 6.0.2
- nx: 16.10.0
+ npm-package-arg: 11.0.2
+ npm-packlist: 8.0.2
+ npm-registry-fetch: 17.1.0
+ nx: 20.8.2
p-map: 4.0.0
p-map-series: 2.1.0
p-pipe: 3.1.0
p-queue: 6.6.2
p-reduce: 2.1.0
p-waterfall: 2.1.1
- pacote: 15.2.0
+ pacote: 18.0.6
pify: 5.0.0
read-cmd-shim: 4.0.0
- read-package-json: 6.0.4
resolve-from: 5.0.0
rimraf: 4.4.1
- semver: 7.6.3
+ semver: 7.7.4
+ set-blocking: 2.0.0
signal-exit: 3.0.7
slash: 3.0.0
- ssri: 9.0.1
- strong-log-transformer: 2.1.0
- tar: 6.1.11
+ ssri: 10.0.6
+ string-width: 4.2.3
+ tar: 6.2.1
temp-dir: 1.0.0
+ through: 2.3.8
+ tinyglobby: 0.2.12
typescript: 5.7.3
upath: 2.0.1
- uuid: 9.0.1
+ uuid: 10.0.0
validate-npm-package-license: 3.0.4
- validate-npm-package-name: 5.0.0
+ validate-npm-package-name: 5.0.1
+ wide-align: 1.1.5
write-file-atomic: 5.0.1
write-pkg: 4.0.0
- yargs: 16.2.0
- yargs-parser: 20.2.4
+ yargs: 17.7.2
+ yargs-parser: 21.1.1
transitivePeerDependencies:
- '@swc-node/register'
- '@swc/core'
+ - '@types/node'
+ - babel-plugin-macros
- bluebird
- debug
- encoding
- supports-color
- leven@3.1.0: {}
-
levn@0.4.1:
dependencies:
prelude-ls: 1.2.1
type-check: 0.4.0
- libnpmaccess@7.0.2:
+ libnpmaccess@8.0.6:
dependencies:
- npm-package-arg: 10.1.0
- npm-registry-fetch: 14.0.5
+ npm-package-arg: 11.0.2
+ npm-registry-fetch: 17.1.0
transitivePeerDependencies:
- supports-color
- libnpmpublish@7.3.0:
+ libnpmpublish@9.0.9:
dependencies:
- ci-info: 3.9.0
- normalize-package-data: 5.0.0
- npm-package-arg: 10.1.0
- npm-registry-fetch: 14.0.5
- proc-log: 3.0.0
- semver: 7.6.3
- sigstore: 1.9.0
+ ci-info: 4.4.0
+ normalize-package-data: 6.0.2
+ npm-package-arg: 11.0.2
+ npm-registry-fetch: 17.1.0
+ proc-log: 4.2.0
+ semver: 7.7.4
+ sigstore: 2.3.1
ssri: 10.0.6
transitivePeerDependencies:
- supports-color
@@ -9486,7 +9657,7 @@ snapshots:
lines-and-columns@1.2.4: {}
- lines-and-columns@2.0.4: {}
+ lines-and-columns@2.0.3: {}
lint-staged@14.0.1(enquirer@2.3.6):
dependencies:
@@ -9508,7 +9679,7 @@ snapshots:
dependencies:
cli-truncate: 3.1.0
colorette: 2.0.20
- eventemitter3: 5.0.1
+ eventemitter3: 5.0.4
log-update: 5.0.1
rfdc: 1.4.1
wrap-ansi: 8.1.0
@@ -9542,21 +9713,11 @@ snapshots:
dependencies:
p-locate: 5.0.0
- lodash.clonedeep@4.5.0: {}
-
- lodash.get@4.4.2: {}
-
- lodash.isequal@4.5.0: {}
-
lodash.ismatch@4.4.0: {}
- lodash.memoize@4.1.2: {}
-
lodash.merge@4.6.2: {}
- lodash.truncate@4.4.2: {}
-
- lodash@4.17.21: {}
+ lodash@4.17.23: {}
log-symbols@4.1.0:
dependencies:
@@ -9565,7 +9726,7 @@ snapshots:
log-symbols@6.0.0:
dependencies:
- chalk: 5.4.1
+ chalk: 5.6.2
is-unicode-supported: 1.3.0
log-update@5.0.1:
@@ -9573,58 +9734,25 @@ snapshots:
ansi-escapes: 5.0.0
cli-cursor: 4.0.0
slice-ansi: 5.0.0
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
wrap-ansi: 8.1.0
- loupe@3.1.2: {}
-
- lowercase-keys@3.0.0: {}
+ loupe@3.2.1: {}
lru-cache@10.4.3: {}
- lru-cache@4.1.5:
- dependencies:
- pseudomap: 1.0.2
- yallist: 2.1.2
-
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
-
lru-cache@6.0.0:
dependencies:
yallist: 4.0.0
- lru-cache@7.18.3: {}
-
- madge@7.0.0(typescript@5.7.3):
- dependencies:
- chalk: 4.1.2
- commander: 7.2.0
- commondir: 1.0.1
- debug: 4.4.0
- dependency-tree: 10.0.9
- ora: 5.4.1
- pluralize: 8.0.0
- precinct: 11.0.5
- pretty-ms: 7.0.1
- rc: 1.2.8
- stream-to-array: 2.3.0
- ts-graphviz: 1.8.2
- walkdir: 0.4.1
- optionalDependencies:
- typescript: 5.7.3
- transitivePeerDependencies:
- - supports-color
-
- magic-string@0.30.17:
+ magic-string@0.30.21:
dependencies:
- '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/sourcemap-codec': 1.5.5
magicast@0.3.5:
dependencies:
- '@babel/parser': 7.26.5
- '@babel/types': 7.26.5
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
source-map-js: 1.2.1
make-dir@2.1.0:
@@ -9634,56 +9762,25 @@ snapshots:
make-dir@4.0.0:
dependencies:
- semver: 7.6.3
-
- make-error@1.3.6: {}
-
- make-fetch-happen@10.2.1:
- dependencies:
- agentkeepalive: 4.6.0
- cacache: 16.1.3
- http-cache-semantics: 4.1.1
- http-proxy-agent: 5.0.0
- https-proxy-agent: 5.0.1
- is-lambda: 1.0.1
- lru-cache: 7.18.3
- minipass: 3.3.6
- minipass-collect: 1.0.2
- minipass-fetch: 2.1.2
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- negotiator: 0.6.4
- promise-retry: 2.0.1
- socks-proxy-agent: 7.0.0
- ssri: 9.0.1
- transitivePeerDependencies:
- - bluebird
- - supports-color
+ semver: 7.7.4
- make-fetch-happen@11.1.1:
+ make-fetch-happen@13.0.1:
dependencies:
- agentkeepalive: 4.6.0
- cacache: 17.1.4
- http-cache-semantics: 4.1.1
- http-proxy-agent: 5.0.0
- https-proxy-agent: 5.0.1
+ '@npmcli/agent': 2.2.2
+ cacache: 18.0.4
+ http-cache-semantics: 4.2.0
is-lambda: 1.0.1
- lru-cache: 7.18.3
- minipass: 5.0.0
+ minipass: 7.1.2
minipass-fetch: 3.0.5
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
negotiator: 0.6.4
+ proc-log: 4.2.0
promise-retry: 2.0.1
- socks-proxy-agent: 7.0.0
ssri: 10.0.6
transitivePeerDependencies:
- supports-color
- makeerror@1.0.12:
- dependencies:
- tmpl: 1.0.5
-
map-obj@1.0.1: {}
map-obj@4.3.0: {}
@@ -9730,35 +9827,31 @@ snapshots:
mimic-function@5.0.1: {}
- mimic-response@3.1.0: {}
-
- mimic-response@4.0.0: {}
-
min-indent@1.0.1: {}
minimatch@3.0.5:
dependencies:
- brace-expansion: 1.1.11
+ brace-expansion: 1.1.12
minimatch@3.1.2:
dependencies:
- brace-expansion: 1.1.11
+ brace-expansion: 1.1.12
minimatch@5.1.6:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimatch@8.0.4:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimatch@9.0.3:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimatch@9.0.5:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimist-options@4.1.0:
dependencies:
@@ -9768,17 +9861,9 @@ snapshots:
minimist@1.2.8: {}
- minipass-collect@1.0.2:
+ minipass-collect@2.0.1:
dependencies:
- minipass: 3.3.6
-
- minipass-fetch@2.1.2:
- dependencies:
- minipass: 3.3.6
- minipass-sized: 1.0.3
- minizlib: 2.1.2
- optionalDependencies:
- encoding: 0.1.13
+ minipass: 7.1.2
minipass-fetch@3.0.5:
dependencies:
@@ -9792,11 +9877,6 @@ snapshots:
dependencies:
minipass: 3.3.6
- minipass-json-stream@1.0.2:
- dependencies:
- jsonparse: 1.3.1
- minipass: 3.3.6
-
minipass-pipeline@1.2.4:
dependencies:
minipass: 3.3.6
@@ -9824,18 +9904,6 @@ snapshots:
modify-values@1.0.1: {}
- module-definition@5.0.1:
- dependencies:
- ast-module-types: 5.0.0
- node-source-walk: 6.0.2
-
- module-lookup-amd@8.0.5:
- dependencies:
- commander: 10.0.1
- glob: 7.2.3
- requirejs: 2.3.7
- requirejs-config-file: 4.0.0
-
ms@2.1.2: {}
ms@2.1.3: {}
@@ -9846,17 +9914,17 @@ snapshots:
array-differ: 3.0.0
array-union: 2.1.0
arrify: 2.0.1
- minimatch: 3.0.5
-
- mustache@4.2.0: {}
+ minimatch: 3.1.2
mute-stream@0.0.8: {}
mute-stream@1.0.0: {}
- mute-stream@2.0.0: {}
+ mute-stream@3.0.0: {}
+
+ nanoid@3.3.11: {}
- nanoid@3.3.8: {}
+ napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {}
@@ -9864,51 +9932,37 @@ snapshots:
neo-async@2.6.2: {}
- node-addon-api@3.2.1: {}
-
node-fetch@2.6.7(encoding@0.1.13):
dependencies:
whatwg-url: 5.0.0
optionalDependencies:
encoding: 0.1.13
- node-gyp-build@4.8.4: {}
-
- node-gyp@9.4.1:
+ node-gyp@10.3.1:
dependencies:
env-paths: 2.2.1
- exponential-backoff: 3.1.1
- glob: 7.2.3
+ exponential-backoff: 3.1.3
+ glob: 10.5.0
graceful-fs: 4.2.11
- make-fetch-happen: 10.2.1
- nopt: 6.0.0
- npmlog: 6.0.2
- rimraf: 3.0.2
- semver: 7.6.3
- tar: 6.2.0
- which: 2.0.2
+ make-fetch-happen: 13.0.1
+ nopt: 7.2.1
+ proc-log: 4.2.0
+ semver: 7.7.4
+ tar: 6.2.1
+ which: 4.0.0
transitivePeerDependencies:
- - bluebird
- supports-color
- node-int64@0.4.0: {}
-
node-machine-id@1.1.12: {}
- node-releases@2.0.19: {}
-
- node-source-walk@6.0.2:
- dependencies:
- '@babel/parser': 7.26.5
-
- nopt@6.0.0:
+ nopt@7.2.1:
dependencies:
- abbrev: 1.1.1
+ abbrev: 2.0.0
normalize-package-data@2.5.0:
dependencies:
hosted-git-info: 2.8.9
- resolve: 1.22.10
+ resolve: 1.22.11
semver: 5.7.2
validate-npm-package-license: 3.0.4
@@ -9916,76 +9970,53 @@ snapshots:
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.16.1
- semver: 7.6.3
+ semver: 7.7.4
validate-npm-package-license: 3.0.4
- normalize-package-data@5.0.0:
+ normalize-package-data@6.0.2:
dependencies:
- hosted-git-info: 6.1.3
- is-core-module: 2.16.1
- semver: 7.6.3
+ hosted-git-info: 7.0.2
+ semver: 7.7.4
validate-npm-package-license: 3.0.4
- normalize-path@3.0.0: {}
-
- normalize-url@8.0.1: {}
-
- npm-bundled@1.1.2:
- dependencies:
- npm-normalize-package-bin: 1.0.1
-
npm-bundled@3.0.1:
dependencies:
npm-normalize-package-bin: 3.0.1
npm-install-checks@6.3.0:
dependencies:
- semver: 7.6.3
-
- npm-normalize-package-bin@1.0.1: {}
+ semver: 7.7.4
npm-normalize-package-bin@3.0.1: {}
- npm-package-arg@10.1.0:
- dependencies:
- hosted-git-info: 6.1.3
- proc-log: 3.0.0
- semver: 7.6.3
- validate-npm-package-name: 5.0.0
-
- npm-package-arg@8.1.1:
+ npm-package-arg@11.0.2:
dependencies:
- hosted-git-info: 3.0.8
- semver: 7.6.3
- validate-npm-package-name: 3.0.0
+ hosted-git-info: 7.0.2
+ proc-log: 4.2.0
+ semver: 7.7.4
+ validate-npm-package-name: 5.0.1
- npm-packlist@5.1.1:
- dependencies:
- glob: 8.1.0
- ignore-walk: 5.0.1
- npm-bundled: 1.1.2
- npm-normalize-package-bin: 1.0.1
-
- npm-packlist@7.0.4:
+ npm-packlist@8.0.2:
dependencies:
ignore-walk: 6.0.5
- npm-pick-manifest@8.0.2:
+ npm-pick-manifest@9.1.0:
dependencies:
npm-install-checks: 6.3.0
npm-normalize-package-bin: 3.0.1
- npm-package-arg: 10.1.0
- semver: 7.6.3
+ npm-package-arg: 11.0.2
+ semver: 7.7.4
- npm-registry-fetch@14.0.5:
+ npm-registry-fetch@17.1.0:
dependencies:
- make-fetch-happen: 11.1.1
- minipass: 5.0.0
+ '@npmcli/redact': 2.0.1
+ jsonparse: 1.3.1
+ make-fetch-happen: 13.0.1
+ minipass: 7.1.2
minipass-fetch: 3.0.5
- minipass-json-stream: 1.0.2
minizlib: 2.1.2
- npm-package-arg: 10.1.0
- proc-log: 3.0.0
+ npm-package-arg: 11.0.2
+ proc-log: 4.2.0
transitivePeerDependencies:
- supports-color
@@ -9995,75 +10026,66 @@ snapshots:
npm-run-path@5.3.0:
dependencies:
- path-key: 4.0.0
-
- npmlog@6.0.2:
- dependencies:
- are-we-there-yet: 3.0.1
- console-control-strings: 1.1.0
- gauge: 4.0.4
- set-blocking: 2.0.0
+ path-key: 4.0.0
- nx@16.10.0:
+ nx@20.8.2:
dependencies:
- '@nrwl/tao': 16.10.0
- '@parcel/watcher': 2.0.4
+ '@napi-rs/wasm-runtime': 0.2.4
'@yarnpkg/lockfile': 1.1.0
- '@yarnpkg/parsers': 3.0.0-rc.46
- '@zkochan/js-yaml': 0.0.6
- axios: 1.7.9
+ '@yarnpkg/parsers': 3.0.2
+ '@zkochan/js-yaml': 0.0.7
+ axios: 1.13.5
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.6.1
cliui: 8.0.1
- dotenv: 16.3.2
- dotenv-expand: 10.0.0
+ dotenv: 16.4.7
+ dotenv-expand: 11.0.7
enquirer: 2.3.6
figures: 3.2.0
flat: 5.0.2
- fs-extra: 11.3.0
- glob: 7.1.4
+ front-matter: 4.0.2
ignore: 5.3.2
jest-diff: 29.7.0
- js-yaml: 4.1.0
jsonc-parser: 3.2.0
- lines-and-columns: 2.0.4
- minimatch: 3.0.5
+ lines-and-columns: 2.0.3
+ minimatch: 9.0.3
node-machine-id: 1.1.12
npm-run-path: 4.0.1
open: 8.4.2
- semver: 7.5.3
+ ora: 5.3.0
+ resolve.exports: 2.0.3
+ semver: 7.7.4
string-width: 4.2.3
- strong-log-transformer: 2.1.0
tar-stream: 2.2.0
- tmp: 0.2.3
+ tmp: 0.2.5
tsconfig-paths: 4.2.0
tslib: 2.8.1
- v8-compile-cache: 2.3.0
+ yaml: 2.8.2
yargs: 17.7.2
yargs-parser: 21.1.1
optionalDependencies:
- '@nx/nx-darwin-arm64': 16.10.0
- '@nx/nx-darwin-x64': 16.10.0
- '@nx/nx-freebsd-x64': 16.10.0
- '@nx/nx-linux-arm-gnueabihf': 16.10.0
- '@nx/nx-linux-arm64-gnu': 16.10.0
- '@nx/nx-linux-arm64-musl': 16.10.0
- '@nx/nx-linux-x64-gnu': 16.10.0
- '@nx/nx-linux-x64-musl': 16.10.0
- '@nx/nx-win32-arm64-msvc': 16.10.0
- '@nx/nx-win32-x64-msvc': 16.10.0
+ '@nx/nx-darwin-arm64': 20.8.2
+ '@nx/nx-darwin-x64': 20.8.2
+ '@nx/nx-freebsd-x64': 20.8.2
+ '@nx/nx-linux-arm-gnueabihf': 20.8.2
+ '@nx/nx-linux-arm64-gnu': 20.8.2
+ '@nx/nx-linux-arm64-musl': 20.8.2
+ '@nx/nx-linux-x64-gnu': 20.8.2
+ '@nx/nx-linux-x64-musl': 20.8.2
+ '@nx/nx-win32-arm64-msvc': 20.8.2
+ '@nx/nx-win32-x64-msvc': 20.8.2
transitivePeerDependencies:
- debug
- object-inspect@1.13.3: {}
+ object-inspect@1.13.4: {}
object-keys@1.1.1: {}
object.assign@4.1.7:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
define-properties: 1.2.1
es-object-atoms: 1.1.1
has-symbols: 1.1.0
@@ -10073,19 +10095,19 @@ snapshots:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-object-atoms: 1.1.1
object.groupby@1.0.3:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
object.values@1.2.1:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
define-properties: 1.2.1
es-object-atoms: 1.1.1
@@ -10111,57 +10133,6 @@ snapshots:
is-docker: 2.2.1
is-wsl: 2.2.0
- openapi-diff@0.23.7(openapi-types@12.1.3):
- dependencies:
- axios: 1.7.9
- commander: 8.3.0
- js-yaml: 4.1.0
- json-schema-diff: 0.18.1
- jsonpointer: 5.0.1
- lodash: 4.17.21
- openapi3-ts: 2.0.2
- swagger-parser: 10.0.3(openapi-types@12.1.3)
- verror: 1.10.1
- transitivePeerDependencies:
- - debug
- - openapi-types
-
- openapi-types@12.1.3: {}
-
- openapi-zod-client@1.18.2:
- dependencies:
- '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3)
- '@liuli-util/fs-extra': 0.1.0
- '@zodios/core': 10.9.6(axios@1.7.9)(zod@3.24.1)
- axios: 1.7.9
- cac: 6.7.14
- handlebars: 4.7.8
- openapi-types: 12.1.3
- openapi3-ts: 3.1.0
- pastable: 2.2.1
- prettier: 2.8.8
- tanu: 0.1.13
- ts-pattern: 5.6.2
- whence: 2.0.1
- zod: 3.24.1
- transitivePeerDependencies:
- - debug
- - react
- - supports-color
- - xstate
-
- openapi3-ts@2.0.2:
- dependencies:
- yaml: 1.10.2
-
- openapi3-ts@3.1.0:
- dependencies:
- yaml: 2.7.0
-
- openapi3-ts@4.4.0:
- dependencies:
- yaml: 2.7.0
-
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -10171,6 +10142,17 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
+ ora@5.3.0:
+ dependencies:
+ bl: 4.1.0
+ chalk: 4.1.2
+ cli-cursor: 3.1.0
+ cli-spinners: 2.9.2
+ is-interactive: 1.0.0
+ log-symbols: 4.1.0
+ strip-ansi: 6.0.1
+ wcwidth: 1.0.1
+
ora@5.4.1:
dependencies:
bl: 4.1.0
@@ -10183,9 +10165,9 @@ snapshots:
strip-ansi: 6.0.1
wcwidth: 1.0.1
- ora@8.1.1:
+ ora@8.2.0:
dependencies:
- chalk: 5.4.1
+ chalk: 5.6.2
cli-cursor: 5.0.0
cli-spinners: 2.9.2
is-interactive: 2.0.0
@@ -10193,18 +10175,14 @@ snapshots:
log-symbols: 6.0.0
stdin-discarder: 0.2.2
string-width: 7.2.0
- strip-ansi: 7.1.0
-
- os-tmpdir@1.0.2: {}
+ strip-ansi: 7.1.2
own-keys@1.0.1:
dependencies:
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
object-keys: 1.1.1
safe-push-apply: 1.0.0
- p-cancelable@3.0.0: {}
-
p-finally@1.0.0: {}
p-limit@1.3.0:
@@ -10260,33 +10238,25 @@ snapshots:
package-json-from-dist@1.0.1: {}
- package-json@8.1.1:
- dependencies:
- got: 12.6.1
- registry-auth-token: 5.0.3
- registry-url: 6.0.1
- semver: 7.6.3
-
- pacote@15.2.0:
+ pacote@18.0.6:
dependencies:
- '@npmcli/git': 4.1.0
+ '@npmcli/git': 5.0.8
'@npmcli/installed-package-contents': 2.1.0
- '@npmcli/promise-spawn': 6.0.2
- '@npmcli/run-script': 6.0.2
- cacache: 17.1.4
+ '@npmcli/package-json': 5.2.0
+ '@npmcli/promise-spawn': 7.0.2
+ '@npmcli/run-script': 8.1.0
+ cacache: 18.0.4
fs-minipass: 3.0.3
- minipass: 5.0.0
- npm-package-arg: 10.1.0
- npm-packlist: 7.0.4
- npm-pick-manifest: 8.0.2
- npm-registry-fetch: 14.0.5
- proc-log: 3.0.0
+ minipass: 7.1.2
+ npm-package-arg: 11.0.2
+ npm-packlist: 8.0.2
+ npm-pick-manifest: 9.1.0
+ npm-registry-fetch: 17.1.0
+ proc-log: 4.2.0
promise-retry: 2.0.1
- read-package-json: 6.0.4
- read-package-json-fast: 3.0.2
- sigstore: 1.9.0
+ sigstore: 2.3.1
ssri: 10.0.6
- tar: 6.2.0
+ tar: 6.2.1
transitivePeerDependencies:
- bluebird
- supports-color
@@ -10295,37 +10265,31 @@ snapshots:
dependencies:
callsites: 3.1.0
- parse-github-url@1.0.3: {}
+ parse-conflict-json@3.0.1:
+ dependencies:
+ json-parse-even-better-errors: 3.0.2
+ just-diff: 6.0.2
+ just-diff-apply: 5.5.0
parse-json@4.0.0:
dependencies:
- error-ex: 1.3.2
+ error-ex: 1.3.4
json-parse-better-errors: 1.0.2
parse-json@5.2.0:
dependencies:
- '@babel/code-frame': 7.26.2
- error-ex: 1.3.2
+ '@babel/code-frame': 7.29.0
+ error-ex: 1.3.4
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
- parse-ms@2.1.0: {}
-
- parse-path@7.0.0:
+ parse-path@7.1.0:
dependencies:
- protocols: 2.0.1
+ protocols: 2.0.2
parse-url@8.1.0:
dependencies:
- parse-path: 7.0.0
-
- pastable@2.2.1:
- dependencies:
- '@babel/core': 7.26.0
- ts-toolbelt: 9.6.0
- type-fest: 3.13.1
- transitivePeerDependencies:
- - supports-color
+ parse-path: 7.1.0
path-exists@3.0.0: {}
@@ -10350,16 +10314,16 @@ snapshots:
path-type@4.0.0: {}
- path-type@5.0.0: {}
+ pathe@2.0.3: {}
- pathe@2.0.2: {}
-
- pathval@2.0.0: {}
+ pathval@2.0.1: {}
picocolors@1.1.1: {}
picomatch@2.3.1: {}
+ picomatch@4.0.3: {}
+
pidtree@0.6.0: {}
pify@2.3.0: {}
@@ -10370,57 +10334,32 @@ snapshots:
pify@5.0.0: {}
- pirates@4.0.6: {}
-
pkg-dir@4.2.0:
dependencies:
find-up: 4.1.0
pluralize@8.0.0: {}
- possible-typed-array-names@1.0.0: {}
+ possible-typed-array-names@1.1.0: {}
- postcss-values-parser@6.0.2(postcss@8.5.1):
+ postcss-selector-parser@6.1.2:
dependencies:
- color-name: 1.1.4
- is-url-superb: 4.0.0
- postcss: 8.5.1
- quote-unquote: 1.0.0
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
- postcss@8.5.1:
+ postcss@8.5.6:
dependencies:
- nanoid: 3.3.8
+ nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
- precinct@11.0.5:
- dependencies:
- '@dependents/detective-less': 4.1.0
- commander: 10.0.1
- detective-amd: 5.0.2
- detective-cjs: 5.0.1
- detective-es6: 4.0.1
- detective-postcss: 6.1.3
- detective-sass: 5.0.3
- detective-scss: 4.0.3
- detective-stylus: 4.0.0
- detective-typescript: 11.2.0
- module-definition: 5.0.1
- node-source-walk: 6.0.2
- transitivePeerDependencies:
- - supports-color
-
prelude-ls@1.2.1: {}
- prettier-linter-helpers@1.0.0:
+ prettier-linter-helpers@1.0.1:
dependencies:
fast-diff: 1.3.0
- prettier@2.8.8: {}
-
- prettier@3.3.3: {}
-
- prettier@3.4.2: {}
+ prettier@3.8.1: {}
pretty-format@29.7.0:
dependencies:
@@ -10428,14 +10367,16 @@ snapshots:
ansi-styles: 5.2.0
react-is: 18.3.1
- pretty-ms@7.0.1:
- dependencies:
- parse-ms: 2.1.0
-
- proc-log@3.0.0: {}
+ proc-log@4.2.0: {}
process-nextick-args@2.0.1: {}
+ proggy@2.0.0: {}
+
+ promise-all-reject-late@1.0.1: {}
+
+ promise-call-limit@3.0.2: {}
+
promise-inflight@1.0.1: {}
promise-retry@2.0.1:
@@ -10443,42 +10384,20 @@ snapshots:
err-code: 2.0.3
retry: 0.12.0
- prompts@2.4.2:
- dependencies:
- kleur: 3.0.3
- sisteransi: 1.0.5
-
promzard@1.0.2:
dependencies:
read: 3.0.1
- proto-list@1.2.4: {}
-
- protocols@2.0.1: {}
+ protocols@2.0.2: {}
proxy-from-env@1.1.0: {}
- pseudomap@1.0.2: {}
-
punycode@2.3.1: {}
- pure-rand@6.1.0: {}
-
queue-microtask@1.2.3: {}
quick-lru@4.0.1: {}
- quick-lru@5.1.1: {}
-
- quote-unquote@1.0.0: {}
-
- rc@1.2.8:
- dependencies:
- deep-extend: 0.6.0
- ini: 1.3.8
- minimist: 1.2.8
- strip-json-comments: 2.0.1
-
react-is@18.3.1: {}
read-cmd-shim@4.0.0: {}
@@ -10488,13 +10407,6 @@ snapshots:
json-parse-even-better-errors: 3.0.2
npm-normalize-package-bin: 3.0.1
- read-package-json@6.0.4:
- dependencies:
- glob: 10.4.5
- json-parse-even-better-errors: 3.0.2
- normalize-package-data: 5.0.0
- npm-normalize-package-bin: 3.0.1
-
read-pkg-up@3.0.0:
dependencies:
find-up: 2.1.0
@@ -10519,17 +10431,13 @@ snapshots:
parse-json: 5.2.0
type-fest: 0.6.0
- read@2.1.0:
- dependencies:
- mute-stream: 1.0.0
-
read@3.0.1:
dependencies:
mute-stream: 1.0.0
readable-stream@2.3.8:
dependencies:
- core-util-is: 1.0.3
+ core-util-is: 1.0.2
inherits: 2.0.4
isarray: 1.0.0
process-nextick-args: 2.0.1
@@ -10552,15 +10460,13 @@ snapshots:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
get-proto: 1.0.1
which-builtin-type: 1.2.1
- regenerator-runtime@0.14.1: {}
-
regexp.prototype.flags@1.5.4:
dependencies:
call-bind: 1.0.8
@@ -10570,33 +10476,14 @@ snapshots:
gopd: 1.2.0
set-function-name: 2.0.2
- registry-auth-token@5.0.3:
- dependencies:
- '@pnpm/npm-conf': 2.3.1
-
- registry-url@6.0.1:
- dependencies:
- rc: 1.2.8
-
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
- requirejs-config-file@4.0.0:
- dependencies:
- esprima: 4.0.1
- stringify-object: 3.3.0
-
- requirejs@2.3.7: {}
-
- resolve-alpn@1.2.1: {}
-
resolve-cwd@3.0.0:
dependencies:
resolve-from: 5.0.0
- resolve-dependency-path@3.0.2: {}
-
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
@@ -10605,16 +10492,12 @@ snapshots:
resolve.exports@2.0.3: {}
- resolve@1.22.10:
+ resolve@1.22.11:
dependencies:
is-core-module: 2.16.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
- responselike@3.0.0:
- dependencies:
- lowercase-keys: 3.0.0
-
restore-cursor@3.1.0:
dependencies:
onetime: 5.1.2
@@ -10632,7 +10515,7 @@ snapshots:
retry@0.12.0: {}
- reusify@1.0.4: {}
+ reusify@1.1.0: {}
rfdc@1.4.1: {}
@@ -10646,50 +10529,54 @@ snapshots:
rimraf@5.0.10:
dependencies:
- glob: 10.4.5
+ glob: 10.5.0
- rollup@4.31.0:
+ rollup@4.57.1:
dependencies:
- '@types/estree': 1.0.6
+ '@types/estree': 1.0.8
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.31.0
- '@rollup/rollup-android-arm64': 4.31.0
- '@rollup/rollup-darwin-arm64': 4.31.0
- '@rollup/rollup-darwin-x64': 4.31.0
- '@rollup/rollup-freebsd-arm64': 4.31.0
- '@rollup/rollup-freebsd-x64': 4.31.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.31.0
- '@rollup/rollup-linux-arm-musleabihf': 4.31.0
- '@rollup/rollup-linux-arm64-gnu': 4.31.0
- '@rollup/rollup-linux-arm64-musl': 4.31.0
- '@rollup/rollup-linux-loongarch64-gnu': 4.31.0
- '@rollup/rollup-linux-powerpc64le-gnu': 4.31.0
- '@rollup/rollup-linux-riscv64-gnu': 4.31.0
- '@rollup/rollup-linux-s390x-gnu': 4.31.0
- '@rollup/rollup-linux-x64-gnu': 4.31.0
- '@rollup/rollup-linux-x64-musl': 4.31.0
- '@rollup/rollup-win32-arm64-msvc': 4.31.0
- '@rollup/rollup-win32-ia32-msvc': 4.31.0
- '@rollup/rollup-win32-x64-msvc': 4.31.0
+ '@rollup/rollup-android-arm-eabi': 4.57.1
+ '@rollup/rollup-android-arm64': 4.57.1
+ '@rollup/rollup-darwin-arm64': 4.57.1
+ '@rollup/rollup-darwin-x64': 4.57.1
+ '@rollup/rollup-freebsd-arm64': 4.57.1
+ '@rollup/rollup-freebsd-x64': 4.57.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.57.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.57.1
+ '@rollup/rollup-linux-arm64-gnu': 4.57.1
+ '@rollup/rollup-linux-arm64-musl': 4.57.1
+ '@rollup/rollup-linux-loong64-gnu': 4.57.1
+ '@rollup/rollup-linux-loong64-musl': 4.57.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.57.1
+ '@rollup/rollup-linux-ppc64-musl': 4.57.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.57.1
+ '@rollup/rollup-linux-riscv64-musl': 4.57.1
+ '@rollup/rollup-linux-s390x-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-musl': 4.57.1
+ '@rollup/rollup-openbsd-x64': 4.57.1
+ '@rollup/rollup-openharmony-arm64': 4.57.1
+ '@rollup/rollup-win32-arm64-msvc': 4.57.1
+ '@rollup/rollup-win32-ia32-msvc': 4.57.1
+ '@rollup/rollup-win32-x64-gnu': 4.57.1
+ '@rollup/rollup-win32-x64-msvc': 4.57.1
fsevents: 2.3.3
run-async@2.4.1: {}
- run-async@3.0.0: {}
-
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
- rxjs@7.8.1:
+ rxjs@7.8.2:
dependencies:
tslib: 2.8.1
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
- get-intrinsic: 1.2.7
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
has-symbols: 1.1.0
isarray: 2.0.5
@@ -10704,30 +10591,17 @@ snapshots:
safe-regex-test@1.1.0:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
is-regex: 1.2.1
safer-buffer@2.1.2: {}
- sass-lookup@5.0.1:
- dependencies:
- commander: 10.0.1
-
- sembear@0.5.2:
- dependencies:
- '@types/semver': 6.2.7
- semver: 6.3.1
-
semver@5.7.2: {}
semver@6.3.1: {}
- semver@7.5.3:
- dependencies:
- lru-cache: 6.0.0
-
- semver@7.6.3: {}
+ semver@7.7.4: {}
set-blocking@2.0.0: {}
@@ -10736,7 +10610,7 @@ snapshots:
define-data-property: 1.1.4
es-errors: 1.3.0
function-bind: 1.1.2
- get-intrinsic: 1.2.7
+ get-intrinsic: 1.3.0
gopd: 1.2.0
has-property-descriptors: 1.0.2
@@ -10757,42 +10631,36 @@ snapshots:
dependencies:
kind-of: 6.0.3
- shebang-command@1.2.0:
- dependencies:
- shebang-regex: 1.0.0
-
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
- shebang-regex@1.0.0: {}
-
shebang-regex@3.0.0: {}
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
- object-inspect: 1.13.3
+ object-inspect: 1.13.4
side-channel-map@1.0.1:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
- get-intrinsic: 1.2.7
- object-inspect: 1.13.3
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
side-channel-weakmap@1.0.2:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
- get-intrinsic: 1.2.7
- object-inspect: 1.13.3
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
side-channel-map: 1.0.1
side-channel@1.1.0:
dependencies:
es-errors: 1.3.0
- object-inspect: 1.13.3
+ object-inspect: 1.13.4
side-channel-list: 1.0.0
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
@@ -10803,46 +10671,37 @@ snapshots:
signal-exit@4.1.0: {}
- sigstore@1.9.0:
+ sigstore@2.3.1:
dependencies:
- '@sigstore/bundle': 1.1.0
- '@sigstore/protobuf-specs': 0.2.1
- '@sigstore/sign': 1.0.0
- '@sigstore/tuf': 1.0.3
- make-fetch-happen: 11.1.1
+ '@sigstore/bundle': 2.3.2
+ '@sigstore/core': 1.1.0
+ '@sigstore/protobuf-specs': 0.3.3
+ '@sigstore/sign': 2.3.2
+ '@sigstore/tuf': 2.3.4
+ '@sigstore/verify': 1.2.1
transitivePeerDependencies:
- supports-color
- sisteransi@1.0.5: {}
-
slash@3.0.0: {}
- slash@5.1.0: {}
-
- slice-ansi@4.0.0:
- dependencies:
- ansi-styles: 4.3.0
- astral-regex: 2.0.0
- is-fullwidth-code-point: 3.0.0
-
slice-ansi@5.0.0:
dependencies:
- ansi-styles: 6.2.1
+ ansi-styles: 6.2.3
is-fullwidth-code-point: 4.0.0
smart-buffer@4.2.0: {}
- socks-proxy-agent@7.0.0:
+ socks-proxy-agent@8.0.5:
dependencies:
- agent-base: 6.0.2
- debug: 4.4.0
- socks: 2.8.3
+ agent-base: 7.1.4
+ debug: 4.4.3
+ socks: 2.8.7
transitivePeerDependencies:
- supports-color
- socks@2.8.3:
+ socks@2.8.7:
dependencies:
- ip-address: 9.0.5
+ ip-address: 10.1.0
smart-buffer: 4.2.0
sort-keys@2.0.0:
@@ -10851,31 +10710,21 @@ snapshots:
source-map-js@1.2.1: {}
- source-map-support@0.5.13:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
source-map@0.6.1: {}
- spawndamnit@2.0.0:
- dependencies:
- cross-spawn: 5.1.0
- signal-exit: 3.0.7
-
spdx-correct@3.2.0:
dependencies:
spdx-expression-parse: 3.0.1
- spdx-license-ids: 3.0.21
+ spdx-license-ids: 3.0.22
spdx-exceptions@2.5.0: {}
spdx-expression-parse@3.0.1:
dependencies:
spdx-exceptions: 2.5.0
- spdx-license-ids: 3.0.21
+ spdx-license-ids: 3.0.22
- spdx-license-ids@3.0.21: {}
+ spdx-license-ids@3.0.22: {}
split2@3.2.2:
dependencies:
@@ -10887,39 +10736,25 @@ snapshots:
sprintf-js@1.0.3: {}
- sprintf-js@1.1.3: {}
-
ssri@10.0.6:
dependencies:
minipass: 7.1.2
- ssri@9.0.1:
- dependencies:
- minipass: 3.3.6
-
- stable-hash@0.0.4: {}
-
- stack-utils@2.0.6:
- dependencies:
- escape-string-regexp: 2.0.0
+ stable-hash@0.0.5: {}
stackback@0.0.2: {}
- std-env@3.8.0: {}
+ std-env@3.10.0: {}
stdin-discarder@0.2.2: {}
- stream-to-array@2.3.0:
+ stop-iteration-iterator@1.1.0:
dependencies:
- any-promise: 1.3.0
+ es-errors: 1.3.0
+ internal-slot: 1.1.0
string-argv@0.3.2: {}
- string-length@4.0.2:
- dependencies:
- char-regex: 1.0.2
- strip-ansi: 6.0.1
-
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -10930,28 +10765,28 @@ snapshots:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
string-width@7.2.0:
dependencies:
- emoji-regex: 10.4.0
- get-east-asian-width: 1.3.0
- strip-ansi: 7.1.0
+ emoji-regex: 10.6.0
+ get-east-asian-width: 1.4.0
+ strip-ansi: 7.1.2
string.prototype.trim@1.2.10:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
define-data-property: 1.1.4
define-properties: 1.2.1
- es-abstract: 1.23.9
+ es-abstract: 1.24.1
es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2
string.prototype.trimend@1.0.9:
dependencies:
call-bind: 1.0.8
- call-bound: 1.0.3
+ call-bound: 1.0.4
define-properties: 1.2.1
es-object-atoms: 1.1.1
@@ -10969,19 +10804,13 @@ snapshots:
dependencies:
safe-buffer: 5.2.1
- stringify-object@3.3.0:
- dependencies:
- get-own-enumerable-property-symbols: 3.0.2
- is-obj: 1.0.1
- is-regexp: 1.0.0
-
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
- strip-ansi@7.1.0:
+ strip-ansi@7.1.2:
dependencies:
- ansi-regex: 6.1.0
+ ansi-regex: 6.2.2
strip-bom@3.0.0: {}
@@ -10995,78 +10824,31 @@ snapshots:
dependencies:
min-indent: 1.0.1
- strip-json-comments@2.0.1: {}
-
strip-json-comments@3.1.1: {}
- strong-log-transformer@2.1.0:
+ strip-literal@3.1.0:
dependencies:
- duplexer: 0.1.2
- minimist: 1.2.8
- through: 2.3.8
-
- stylus-lookup@5.0.1:
- dependencies:
- commander: 10.0.1
-
- supports-color@5.5.0:
- dependencies:
- has-flag: 3.0.0
+ js-tokens: 9.0.1
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
- supports-color@8.1.1:
- dependencies:
- has-flag: 4.0.0
-
supports-preserve-symlinks-flag@1.0.0: {}
- swagger-parser@10.0.3(openapi-types@12.1.3):
- dependencies:
- '@apidevtools/swagger-parser': 10.0.3(openapi-types@12.1.3)
- transitivePeerDependencies:
- - openapi-types
-
- synckit@0.9.2:
- dependencies:
- '@pkgr/core': 0.1.1
- tslib: 2.8.1
-
- table@6.9.0:
- dependencies:
- ajv: 8.17.1
- lodash.truncate: 4.4.2
- slice-ansi: 4.0.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
- tanu@0.1.13:
+ synckit@0.11.12:
dependencies:
- tslib: 2.8.1
- typescript: 4.9.5
-
- tapable@2.2.1: {}
+ '@pkgr/core': 0.2.9
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
- end-of-stream: 1.4.4
+ end-of-stream: 1.4.5
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
- tar@6.1.11:
- dependencies:
- chownr: 2.0.0
- fs-minipass: 2.1.0
- minipass: 3.3.6
- minizlib: 2.1.2
- mkdirp: 1.0.4
- yallist: 4.0.0
-
- tar@6.2.0:
+ tar@6.2.1:
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
@@ -11077,22 +10859,10 @@ snapshots:
temp-dir@1.0.0: {}
- temporal-polyfill@0.2.5:
- dependencies:
- temporal-spec: 0.2.4
-
- temporal-spec@0.2.4: {}
-
- test-exclude@6.0.0:
- dependencies:
- '@istanbuljs/schema': 0.1.3
- glob: 7.2.3
- minimatch: 3.1.2
-
test-exclude@7.0.1:
dependencies:
'@istanbuljs/schema': 0.1.3
- glob: 10.4.5
+ glob: 10.5.0
minimatch: 9.0.5
text-extensions@1.9.0: {}
@@ -11110,19 +10880,23 @@ snapshots:
tinyexec@0.3.2: {}
- tinypool@1.0.2: {}
+ tinyglobby@0.2.12:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
- tinyrainbow@2.0.0: {}
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
- tinyspy@3.0.2: {}
+ tinypool@1.1.1: {}
- tmp@0.0.33:
- dependencies:
- os-tmpdir: 1.0.2
+ tinyrainbow@2.0.0: {}
- tmp@0.2.3: {}
+ tinyspy@4.0.4: {}
- tmpl@1.0.5: {}
+ tmp@0.2.5: {}
to-regex-range@5.0.1:
dependencies:
@@ -11130,55 +10904,14 @@ snapshots:
tr46@0.0.3: {}
+ treeverse@3.0.0: {}
+
trim-newlines@3.0.1: {}
ts-api-utils@1.4.3(typescript@5.7.3):
dependencies:
typescript: 5.7.3
- ts-graphviz@1.8.2: {}
-
- ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3)))(typescript@5.7.3):
- dependencies:
- bs-logger: 0.2.6
- ejs: 3.1.10
- fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@22.10.7)(ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3))
- jest-util: 29.7.0
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.6.3
- typescript: 5.7.3
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.26.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.26.0)
-
- ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3):
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.11
- '@tsconfig/node12': 1.0.11
- '@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.4
- '@types/node': 22.10.7
- acorn: 8.14.0
- acorn-walk: 8.3.4
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- typescript: 5.7.3
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
-
- ts-pattern@5.6.2: {}
-
- ts-toolbelt@9.6.0: {}
-
tsconfig-paths@3.15.0:
dependencies:
'@types/json5': 0.0.29
@@ -11192,20 +10925,13 @@ snapshots:
minimist: 1.2.8
strip-bom: 3.0.0
- tslib@1.14.1: {}
-
tslib@2.8.1: {}
- tsutils@3.21.0(typescript@5.7.3):
+ tuf-js@2.2.1:
dependencies:
- tslib: 1.14.1
- typescript: 5.7.3
-
- tuf-js@1.1.7:
- dependencies:
- '@tufjs/models': 1.0.4
- debug: 4.4.0
- make-fetch-happen: 11.1.1
+ '@tufjs/models': 2.0.1
+ debug: 4.4.3
+ make-fetch-happen: 13.0.1
transitivePeerDependencies:
- supports-color
@@ -11213,8 +10939,6 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
- type-detect@4.0.8: {}
-
type-fest@0.18.1: {}
type-fest@0.20.2: {}
@@ -11229,18 +10953,16 @@ snapshots:
type-fest@1.4.0: {}
- type-fest@3.13.1: {}
-
typed-array-buffer@1.0.3:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
es-errors: 1.3.0
is-typed-array: 1.1.15
typed-array-byte-length@1.0.3:
dependencies:
call-bind: 1.0.8
- for-each: 0.3.3
+ for-each: 0.3.5
gopd: 1.2.0
has-proto: 1.2.0
is-typed-array: 1.1.15
@@ -11249,7 +10971,7 @@ snapshots:
dependencies:
available-typed-arrays: 1.0.7
call-bind: 1.0.8
- for-each: 0.3.3
+ for-each: 0.3.5
gopd: 1.2.0
has-proto: 1.2.0
is-typed-array: 1.1.15
@@ -11258,16 +10980,14 @@ snapshots:
typed-array-length@1.0.7:
dependencies:
call-bind: 1.0.8
- for-each: 0.3.3
+ for-each: 0.3.5
gopd: 1.2.0
is-typed-array: 1.1.15
- possible-typed-array-names: 1.0.0
+ possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
typedarray@0.0.6: {}
- typescript@4.9.5: {}
-
typescript@5.7.3: {}
uglify-js@3.19.3:
@@ -11275,44 +10995,50 @@ snapshots:
unbox-primitive@1.1.0:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
has-bigints: 1.1.0
has-symbols: 1.1.0
which-boxed-primitive: 1.1.1
- undici-types@6.20.0: {}
-
- unicorn-magic@0.1.0: {}
-
- unique-filename@2.0.1:
- dependencies:
- unique-slug: 3.0.0
+ undici-types@6.21.0: {}
unique-filename@3.0.0:
dependencies:
unique-slug: 4.0.0
- unique-slug@3.0.0:
- dependencies:
- imurmurhash: 0.1.4
-
unique-slug@4.0.0:
dependencies:
imurmurhash: 0.1.4
universal-user-agent@6.0.1: {}
- universalify@0.1.2: {}
-
universalify@2.0.1: {}
- upath@2.0.1: {}
-
- update-browserslist-db@1.1.2(browserslist@4.24.4):
+ unrs-resolver@1.11.1:
dependencies:
- browserslist: 4.24.4
- escalade: 3.2.0
- picocolors: 1.1.1
+ napi-postinstall: 0.3.4
+ optionalDependencies:
+ '@unrs/resolver-binding-android-arm-eabi': 1.11.1
+ '@unrs/resolver-binding-android-arm64': 1.11.1
+ '@unrs/resolver-binding-darwin-arm64': 1.11.1
+ '@unrs/resolver-binding-darwin-x64': 1.11.1
+ '@unrs/resolver-binding-freebsd-x64': 1.11.1
+ '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1
+ '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1
+ '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-arm64-musl': 1.11.1
+ '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1
+ '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-x64-gnu': 1.11.1
+ '@unrs/resolver-binding-linux-x64-musl': 1.11.1
+ '@unrs/resolver-binding-wasm32-wasi': 1.11.1
+ '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1
+ '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
+ '@unrs/resolver-binding-win32-x64-msvc': 1.11.1
+
+ upath@2.0.1: {}
uri-js@4.4.1:
dependencies:
@@ -11320,46 +11046,22 @@ snapshots:
util-deprecate@1.0.2: {}
- uuid@9.0.1: {}
-
- v8-compile-cache-lib@3.0.1: {}
-
- v8-compile-cache@2.3.0: {}
-
- v8-to-istanbul@9.3.0:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- '@types/istanbul-lib-coverage': 2.0.6
- convert-source-map: 2.0.0
+ uuid@10.0.0: {}
validate-npm-package-license@3.0.4:
dependencies:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
- validate-npm-package-name@3.0.0:
- dependencies:
- builtins: 1.0.3
-
- validate-npm-package-name@5.0.0:
- dependencies:
- builtins: 5.1.0
-
- validator@13.12.0: {}
+ validate-npm-package-name@5.0.1: {}
- verror@1.10.1:
- dependencies:
- assert-plus: 1.0.0
- core-util-is: 1.0.2
- extsprintf: 1.4.1
-
- vite-node@3.0.3(@types/node@22.10.7)(yaml@2.7.0):
+ vite-node@3.2.4(@types/node@22.19.11)(yaml@2.8.2):
dependencies:
cac: 6.7.14
- debug: 4.4.0
- es-module-lexer: 1.6.0
- pathe: 2.0.2
- vite: 6.0.11(@types/node@22.10.7)(yaml@2.7.0)
+ debug: 4.4.3
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 7.3.1(@types/node@22.19.11)(yaml@2.8.2)
transitivePeerDependencies:
- '@types/node'
- jiti
@@ -11374,40 +11076,46 @@ snapshots:
- tsx
- yaml
- vite@6.0.11(@types/node@22.10.7)(yaml@2.7.0):
+ vite@7.3.1(@types/node@22.19.11)(yaml@2.8.2):
dependencies:
- esbuild: 0.24.2
- postcss: 8.5.1
- rollup: 4.31.0
+ esbuild: 0.27.3
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.57.1
+ tinyglobby: 0.2.15
optionalDependencies:
- '@types/node': 22.10.7
+ '@types/node': 22.19.11
fsevents: 2.3.3
- yaml: 2.7.0
-
- vitest@3.0.3(@types/node@22.10.7)(yaml@2.7.0):
- dependencies:
- '@vitest/expect': 3.0.3
- '@vitest/mocker': 3.0.3(vite@6.0.11(@types/node@22.10.7)(yaml@2.7.0))
- '@vitest/pretty-format': 3.0.3
- '@vitest/runner': 3.0.3
- '@vitest/snapshot': 3.0.3
- '@vitest/spy': 3.0.3
- '@vitest/utils': 3.0.3
- chai: 5.1.2
- debug: 4.4.0
- expect-type: 1.1.0
- magic-string: 0.30.17
- pathe: 2.0.2
- std-env: 3.8.0
+ yaml: 2.8.2
+
+ vitest@3.2.4(@types/node@22.19.11)(yaml@2.8.2):
+ dependencies:
+ '@types/chai': 5.2.3
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.11)(yaml@2.8.2))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.3.3
+ debug: 4.4.3
+ expect-type: 1.3.0
+ magic-string: 0.30.21
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
- tinypool: 1.0.2
+ tinyglobby: 0.2.15
+ tinypool: 1.1.1
tinyrainbow: 2.0.0
- vite: 6.0.11(@types/node@22.10.7)(yaml@2.7.0)
- vite-node: 3.0.3(@types/node@22.10.7)(yaml@2.7.0)
+ vite: 7.3.1(@types/node@22.19.11)(yaml@2.8.2)
+ vite-node: 3.2.4(@types/node@22.19.11)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
- '@types/node': 22.10.7
+ '@types/node': 22.19.11
transitivePeerDependencies:
- jiti
- less
@@ -11422,26 +11130,7 @@ snapshots:
- tsx
- yaml
- vscode-jsonrpc@8.2.0: {}
-
- vscode-languageserver-protocol@3.17.5:
- dependencies:
- vscode-jsonrpc: 8.2.0
- vscode-languageserver-types: 3.17.5
-
- vscode-languageserver-textdocument@1.0.12: {}
-
- vscode-languageserver-types@3.17.5: {}
-
- vscode-languageserver@9.0.1:
- dependencies:
- vscode-languageserver-protocol: 3.17.5
-
- walkdir@0.4.1: {}
-
- walker@1.0.8:
- dependencies:
- makeerror: 1.0.12
+ walk-up-path@3.0.1: {}
wcwidth@1.0.1:
dependencies:
@@ -11454,34 +11143,29 @@ snapshots:
tr46: 0.0.3
webidl-conversions: 3.0.1
- whence@2.0.1:
- dependencies:
- '@babel/parser': 7.26.5
- eval-estree-expression: 2.0.3
-
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
- is-boolean-object: 1.2.1
+ is-boolean-object: 1.2.2
is-number-object: 1.1.1
is-string: 1.1.1
is-symbol: 1.1.1
which-builtin-type@1.2.1:
dependencies:
- call-bound: 1.0.3
+ call-bound: 1.0.4
function.prototype.name: 1.1.8
has-tostringtag: 1.0.2
- is-async-function: 2.1.0
+ is-async-function: 2.1.1
is-date-object: 1.1.0
is-finalizationregistry: 1.1.1
- is-generator-function: 1.1.0
+ is-generator-function: 1.1.2
is-regex: 1.2.1
- is-weakref: 1.1.0
+ is-weakref: 1.1.1
isarray: 2.0.5
which-boxed-primitive: 1.1.1
which-collection: 1.0.2
- which-typed-array: 1.1.18
+ which-typed-array: 1.1.20
which-collection@1.0.2:
dependencies:
@@ -11490,26 +11174,23 @@ snapshots:
is-weakmap: 2.0.2
is-weakset: 2.0.4
- which-typed-array@1.1.18:
+ which-typed-array@1.1.20:
dependencies:
available-typed-arrays: 1.0.7
call-bind: 1.0.8
- call-bound: 1.0.3
- for-each: 0.3.3
+ call-bound: 1.0.4
+ for-each: 0.3.5
+ get-proto: 1.0.1
gopd: 1.2.0
has-tostringtag: 1.0.2
- which@1.3.1:
- dependencies:
- isexe: 2.0.0
-
which@2.0.2:
dependencies:
isexe: 2.0.0
- which@3.0.1:
+ which@4.0.0:
dependencies:
- isexe: 2.0.0
+ isexe: 3.1.5
why-is-node-running@2.3.0:
dependencies:
@@ -11538,9 +11219,15 @@ snapshots:
wrap-ansi@8.1.0:
dependencies:
- ansi-styles: 6.2.1
+ ansi-styles: 6.2.3
string-width: 5.1.2
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
+
+ wrap-ansi@9.0.2:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 7.2.0
+ strip-ansi: 7.1.2
wrappy@1.0.2: {}
@@ -11550,11 +11237,6 @@ snapshots:
imurmurhash: 0.1.4
signal-exit: 3.0.7
- write-file-atomic@4.0.2:
- dependencies:
- imurmurhash: 0.1.4
- signal-exit: 3.0.7
-
write-file-atomic@5.0.1:
dependencies:
imurmurhash: 0.1.4
@@ -11579,21 +11261,13 @@ snapshots:
y18n@5.0.8: {}
- yallist@2.1.2: {}
-
- yallist@3.1.1: {}
-
yallist@4.0.0: {}
- yaml@1.10.2: {}
+ yaml-ast-parser@0.0.43: {}
yaml@2.3.1: {}
- yaml@2.5.1: {}
-
- yaml@2.7.0: {}
-
- yargs-parser@20.2.4: {}
+ yaml@2.8.2: {}
yargs-parser@20.2.9: {}
@@ -11619,18 +11293,4 @@ snapshots:
y18n: 5.0.8
yargs-parser: 21.1.1
- yn@3.1.1: {}
-
yocto-queue@0.1.0: {}
-
- yoctocolors-cjs@2.1.2: {}
-
- z-schema@5.0.5:
- dependencies:
- lodash.get: 4.4.2
- lodash.isequal: 4.5.0
- validator: 13.12.0
- optionalDependencies:
- commander: 9.5.0
-
- zod@3.24.1: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 281197a..dee51e9 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,5 +1,2 @@
packages:
- "packages/*"
- - "packages/generators/*"
- - "packages/providers/*"
- - "packages/types/*"
diff --git a/spec-graduate.gif b/spec-graduate.gif
deleted file mode 100644
index 3a040a5..0000000
Binary files a/spec-graduate.gif and /dev/null differ
diff --git a/tests/e2e/01-init.test.ts b/tests/e2e/01-init.test.ts
new file mode 100644
index 0000000..5ba98ae
--- /dev/null
+++ b/tests/e2e/01-init.test.ts
@@ -0,0 +1,133 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ fileExists,
+ readYAML,
+ readJSON,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual init', () => {
+ test('detects OpenAPI spec and scaffolds config', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.openapi.yaml'));
+
+ const result = run('init', dir);
+
+ // Assert: config created
+ expect(fileExists(dir, 'contractual.yaml')).toBe(true);
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array<{ type: string; path: string }> };
+ expect(config.contracts).toHaveLength(1);
+ expect(config.contracts[0].type).toBe('openapi');
+ expect(config.contracts[0].path).toContain('api.openapi.yaml');
+
+ // Assert: .contractual directory created
+ expect(fileExists(dir, '.contractual/versions.json')).toBe(true);
+ expect(fileExists(dir, '.contractual/changesets')).toBe(true);
+ expect(fileExists(dir, '.contractual/snapshots')).toBe(true);
+
+ // Assert: versions.json is populated with initial version
+ const versions = readJSON(dir, '.contractual/versions.json') as Record;
+ const contractName = Object.keys(versions)[0];
+ expect(contractName).toBeDefined();
+ expect(versions[contractName].version).toBe('0.0.0');
+
+ // Assert: stdout confirms detection
+ expect(result.stdout).toMatch(/found|detected|initialized/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects JSON Schema by extension', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.schema.json'));
+
+ run('init', dir);
+
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array<{ type: string }> };
+ expect(config.contracts).toHaveLength(1);
+ expect(config.contracts[0].type).toBe('json-schema');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects multiple spec types in one repo', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.openapi.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.schema.json'));
+
+ run('init', dir);
+
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array<{ type: string }> };
+ expect(config.contracts).toHaveLength(2);
+
+ const types = config.contracts.map((c) => c.type).sort();
+ expect(types).toEqual(['json-schema', 'openapi']);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles already initialized gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.openapi.yaml'));
+
+ run('init', dir);
+
+ // Second init should succeed with informational message (use --force to reinitialize)
+ const result = run('init', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/already initialized|all contracts have snapshots/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles repo with no specs', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ const result = run('init', dir);
+
+ // Should still complete (maybe with a warning)
+ expect(result.exitCode).toBe(0);
+
+ // Config may or may not be created with empty contracts
+ if (fileExists(dir, 'contractual.yaml')) {
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array };
+ expect(config.contracts).toHaveLength(0);
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('uses parent directory name for generic spec names', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Use "openapi.yaml" (generic name) in "orders" directory
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'orders/openapi.yaml'));
+
+ run('init', dir);
+
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array<{ name: string }> };
+ expect(config.contracts).toHaveLength(1);
+ // Should use "orders" as the name, not "openapi"
+ expect(config.contracts[0].name).toBe('orders');
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/02-lint.test.ts b/tests/e2e/02-lint.test.ts
new file mode 100644
index 0000000..993fabe
--- /dev/null
+++ b/tests/e2e/02-lint.test.ts
@@ -0,0 +1,192 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual lint', () => {
+ // Note: No built-in linters are registered yet in linterRegistry.
+ // All contracts are skipped with "no linter available for {type}" message.
+ // These tests verify the CLI handles this gracefully (exit 0, no errors).
+
+ test('OpenAPI spec linted with Spectral returns errors for petstore fixture', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // OpenAPI linter (Spectral) is registered and finds errors in petstore fixture
+ const result = run('lint --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.results).toHaveLength(1);
+ expect(parsed.results[0].errors.length).toBeGreaterThan(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('JSON Schema without registered linter exits successfully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // No linter registered = contract is skipped, exit 0
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ // Skip: No linters are registered, so invalid schemas cannot be validated
+ test.skip('lint reports errors for invalid JSON Schema and exits 1', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'bad-schema',
+ type: 'json-schema',
+ path: 'schemas/bad.json',
+ },
+ ]);
+ // Write an intentionally invalid JSON Schema
+ writeFile(
+ dir,
+ 'schemas/bad.json',
+ JSON.stringify({
+ type: 'objekt', // typo - invalid type value
+ properties: {
+ id: { type: 123 }, // type should be string, not number
+ },
+ })
+ );
+
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/error/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint --format json outputs valid JSON', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('lint --format json', dir);
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed).toHaveProperty('results');
+ expect(Array.isArray(parsed.results)).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint with disabled linter skips contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ lint: false,
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // With --format json, disabled contracts are not included in results
+ const result = run('lint --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ // Results should be empty since contract is disabled
+ expect(parsed.results).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint --contract filters to single contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ { name: 'schema', type: 'json-schema', path: 'schemas/order.json' },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // OpenAPI linter runs for 'api' contract, petstore has lint errors
+ const result = run('lint --contract api --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ const parsed = JSON.parse(result.stdout);
+ // Should have exactly 1 result (the filtered 'api' contract)
+ expect(parsed.results).toHaveLength(1);
+ expect(parsed.results[0].contract).toBe('api');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint reports error for non-existent contract name', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ const result = run('lint --contract nonexistent', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/not found/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint fails with empty contracts array due to schema validation', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Config schema requires minItems: 1 for contracts array
+ setupRepoWithConfig(dir, []);
+
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ // Should fail config validation
+ expect(result.stdout + result.stderr).toMatch(/contracts|validation|invalid/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/03-breaking.test.ts b/tests/e2e/03-breaking.test.ts
new file mode 100644
index 0000000..bfff362
--- /dev/null
+++ b/tests/e2e/03-breaking.test.ts
@@ -0,0 +1,274 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual breaking', () => {
+ test('no snapshot β reports first version, no breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ // First version with no snapshot shows "No changes detected"
+ expect(result.stdout).toMatch(/no changes detected/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects breaking change in JSON Schema (field removed)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ // Put base as snapshot (simulating a previous release)
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ // Put breaking variant as current spec
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects non-breaking change (optional field added)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+
+ const result = run('breaking', dir);
+ // Non-breaking = exit 0 (only breaking exits 1)
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/non-breaking|minor|no breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('no changes detected when spec is identical', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no.*change|no breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--format json returns structured output', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed).toHaveProperty('results');
+ expect(parsed).toHaveProperty('hasBreaking');
+ expect(parsed.hasBreaking).toBe(true);
+ expect(Array.isArray(parsed.results)).toBe(true);
+ expect(parsed.results[0]).toHaveProperty('changes');
+ expect(parsed.results[0]).toHaveProperty('summary');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects type change as breaking', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture('json-schema/order-type-changed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking|type/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--contract filters to single contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ // Set up snapshots for both
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/user-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Breaking change in order, no change in user
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Check only user-schema - should pass
+ const result = run('breaking --contract user-schema', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking detection disabled for contract skips it', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ breaking: false,
+ },
+ ]);
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ // Disabled contracts show "No changes detected"
+ expect(result.stdout).toMatch(/no changes detected/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/04-changeset.test.ts b/tests/e2e/04-changeset.test.ts
new file mode 100644
index 0000000..cbd87c4
--- /dev/null
+++ b/tests/e2e/04-changeset.test.ts
@@ -0,0 +1,362 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual changeset', () => {
+ test('auto-generates changeset from detected breaking changes (major bump)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Put base as snapshot (simulating a previous release)
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Put breaking variant as current spec (field removed)
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // A changeset file should exist
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThanOrEqual(1);
+
+ // Parse the changeset
+ const content = readFile(dir, `.contractual/changesets/${changesets[0]}`);
+
+ // Frontmatter should have major bump
+ expect(content).toMatch(/"order-schema":\s*major/);
+
+ // Body should contain the contract name section
+ expect(content).toMatch(/##\s*order-schema/);
+
+ // Body should mention BREAKING
+ expect(content).toMatch(/\*\*\[BREAKING\]\*\*/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('auto-generates minor changeset for non-breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Put base as snapshot
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Put non-breaking variant as current spec (optional field added)
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThanOrEqual(1);
+
+ const content = readFile(dir, `.contractual/changesets/${changesets[0]}`);
+
+ // Frontmatter should have minor bump (not major)
+ expect(content).toMatch(/"order-schema":\s*minor/);
+
+ // Body should contain the contract section
+ expect(content).toMatch(/##\s*order-schema/);
+
+ // Body should mention minor or non-breaking change
+ expect(content).toMatch(/\*\*\[minor\]\*\*/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('no changes -> no changeset created, clean exit', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Put base as snapshot
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ // Put identical spec as current
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Output should indicate no changes
+ expect(result.stdout).toMatch(/no changes/i);
+
+ // No changeset files should be created (except .gitkeep if present)
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('changeset for multiple contracts in one file', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ // Both have snapshots at v1 (using order-base as template for both)
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/user-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Breaking change to order (field removed), non-breaking to user (optional field added)
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/user.json')
+ );
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThanOrEqual(1);
+
+ const content = readFile(dir, `.contractual/changesets/${changesets[0]}`);
+
+ // Should have both contracts in the frontmatter
+ expect(content).toMatch(/"order-schema":\s*major/);
+ expect(content).toMatch(/"user-schema":\s*minor/);
+
+ // Should have sections for both contracts
+ expect(content).toMatch(/##\s*order-schema/);
+ expect(content).toMatch(/##\s*user-schema/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('first version contract (no snapshot) is skipped', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // No snapshot exists - first version
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Empty versions
+ writeFile(dir, '.contractual/versions.json', '{}');
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // No changes to detect without a snapshot
+ expect(result.stdout).toMatch(/no changes/i);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('changeset with type change (breaking)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Type changed (breaking)
+ copyFixture('json-schema/order-type-changed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets.length).toBeGreaterThanOrEqual(1);
+
+ const content = readFile(dir, `.contractual/changesets/${changesets[0]}`);
+
+ // Should be major bump
+ expect(content).toMatch(/"order-schema":\s*major/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('contract with breaking detection disabled is skipped', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ breaking: false,
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Breaking change that would normally be detected
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // No changeset should be created since breaking detection is disabled
+ expect(result.stdout).toMatch(/no changes/i);
+
+ const changesets = listFiles(dir, '.contractual/changesets').filter((f) => f.endsWith('.md'));
+ expect(changesets).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('changeset output indicates created file path', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Output should mention the changeset file was created
+ expect(result.stdout).toMatch(/created.*changeset/i);
+ expect(result.stdout).toMatch(/\.contractual\/changesets/);
+ expect(result.stdout).toMatch(/\.md/);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/05-version.test.ts b/tests/e2e/05-version.test.ts
new file mode 100644
index 0000000..3fc73c3
--- /dev/null
+++ b/tests/e2e/05-version.test.ts
@@ -0,0 +1,488 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ listFiles,
+ fileExists,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual version', () => {
+ test('consumes changeset, bumps version, updates snapshot, writes changelog', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Setup repo with a contract
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Set initial version
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a changeset
+ writeFile(
+ dir,
+ '.contractual/changesets/add-notes-field.md',
+ `---
+"order-schema": minor
+---
+## order-schema
+- Added optional notes field to order
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds
+ expect(result.exitCode).toBe(0);
+
+ // Assert: version bumped to 1.1.0 (minor bump from 1.0.0)
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string; released: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.1.0');
+ expect(versions['order-schema'].released).toBeDefined();
+
+ // Assert: snapshot created/updated
+ expect(fileExists(dir, '.contractual/snapshots/order-schema.json')).toBe(true);
+
+ // Assert: changelog created with entry
+ expect(fileExists(dir, 'CHANGELOG.md')).toBe(true);
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toContain('# Changelog');
+ expect(changelog).toContain('[order-schema] v1.1.0');
+ expect(changelog).toContain('Added optional notes field');
+
+ // Assert: changeset file removed
+ const changesetFiles = listFiles(dir, '.contractual/changesets');
+ expect(changesetFiles).not.toContain('add-notes-field.md');
+
+ // Assert: stdout confirms version bump
+ expect(result.stdout).toMatch(/1\.0\.0.*->.*1\.1\.0/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('multiple changesets: highest bump wins (major > minor > patch)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api-schema',
+ type: 'json-schema',
+ path: 'schemas/api.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/api.json'));
+
+ // Set initial version
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'api-schema': { version: '2.5.3', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create multiple changesets with different bump types
+ // Changeset 1: patch bump
+ writeFile(
+ dir,
+ '.contractual/changesets/fix-typo.md',
+ `---
+"api-schema": patch
+---
+## api-schema
+- Fixed typo in description
+`
+ );
+
+ // Changeset 2: minor bump
+ writeFile(
+ dir,
+ '.contractual/changesets/add-field.md',
+ `---
+"api-schema": minor
+---
+## api-schema
+- Added new optional field
+`
+ );
+
+ // Changeset 3: major bump (should win)
+ writeFile(
+ dir,
+ '.contractual/changesets/breaking-change.md',
+ `---
+"api-schema": major
+---
+## api-schema
+- Removed deprecated endpoint (BREAKING)
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds
+ expect(result.exitCode).toBe(0);
+
+ // Assert: major bump applied (2.5.3 -> 3.0.0)
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api-schema'].version).toBe('3.0.0');
+
+ // Assert: all changesets consumed
+ const changesetFiles = listFiles(dir, '.contractual/changesets');
+ expect(changesetFiles).toHaveLength(0);
+
+ // Assert: changelog contains all changes
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toContain('v3.0.0');
+ expect(changelog).toContain('Fixed typo');
+ expect(changelog).toContain('Added new optional field');
+ expect(changelog).toContain('Removed deprecated endpoint');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('no changesets does nothing', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Set version but no changesets
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds (no-op)
+ expect(result.exitCode).toBe(0);
+
+ // Assert: version unchanged
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.0.0');
+
+ // Assert: no changelog created
+ expect(fileExists(dir, 'CHANGELOG.md')).toBe(false);
+
+ // Assert: stdout indicates nothing to do
+ expect(result.stdout).toMatch(/no.*changeset|nothing/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('first version: 0.0.0 -> 1.0.0 on major', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'new-api',
+ type: 'json-schema',
+ path: 'schemas/new-api.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/new-api.json'));
+
+ // No initial version (first release)
+ // versions.json is empty (setup creates empty object)
+
+ // Create changeset with major bump
+ writeFile(
+ dir,
+ '.contractual/changesets/initial-release.md',
+ `---
+"new-api": major
+---
+## new-api
+- Initial release of the API
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds
+ expect(result.exitCode).toBe(0);
+
+ // Assert: version is 1.0.0 (major bump from implicit 0.0.0)
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['new-api'].version).toBe('1.0.0');
+
+ // Assert: snapshot created
+ expect(fileExists(dir, '.contractual/snapshots/new-api.json')).toBe(true);
+
+ // Assert: changelog created
+ expect(fileExists(dir, 'CHANGELOG.md')).toBe(true);
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toContain('[new-api] v1.0.0');
+ expect(changelog).toContain('Initial release');
+
+ // Assert: stdout shows bump from 0.0.0
+ expect(result.stdout).toMatch(/0\.0\.0.*->.*1\.0\.0/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('changelog appends, does not overwrite existing entries', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api',
+ type: 'json-schema',
+ path: 'schemas/api.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/api.json'));
+
+ // Set initial version
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create existing changelog with previous entries
+ writeFile(
+ dir,
+ 'CHANGELOG.md',
+ `# Changelog
+
+## [api] v1.0.0 - 2026-01-01
+
+- Initial release with core features
+- Added authentication support
+`
+ );
+
+ // Create a new changeset
+ writeFile(
+ dir,
+ '.contractual/changesets/add-feature.md',
+ `---
+"api": minor
+---
+## api
+- Added pagination support
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds
+ expect(result.exitCode).toBe(0);
+
+ // Assert: version bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api'].version).toBe('1.1.0');
+
+ // Assert: changelog preserved old entries AND has new entry
+ const changelog = readFile(dir, 'CHANGELOG.md');
+
+ // New entry should be present
+ expect(changelog).toContain('[api] v1.1.0');
+ expect(changelog).toContain('Added pagination support');
+
+ // Old entries should still be present
+ expect(changelog).toContain('[api] v1.0.0');
+ expect(changelog).toContain('Initial release with core features');
+ expect(changelog).toContain('Added authentication support');
+
+ // New entry should come before old entry (prepended)
+ const v110Index = changelog.indexOf('[api] v1.1.0');
+ const v100Index = changelog.indexOf('[api] v1.0.0');
+ expect(v110Index).toBeLessThan(v100Index);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles multiple contracts in one changeset', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'orders-api',
+ type: 'json-schema',
+ path: 'schemas/orders.json',
+ },
+ {
+ name: 'users-api',
+ type: 'json-schema',
+ path: 'schemas/users.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/orders.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/users.json'));
+
+ // Set initial versions
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'orders-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'users-api': { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create changeset affecting both contracts
+ writeFile(
+ dir,
+ '.contractual/changesets/shared-update.md',
+ `---
+"orders-api": minor
+"users-api": patch
+---
+## orders-api
+- Added bulk operations endpoint
+
+## users-api
+- Fixed validation message
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds
+ expect(result.exitCode).toBe(0);
+
+ // Assert: both versions bumped appropriately
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['orders-api'].version).toBe('1.1.0');
+ expect(versions['users-api'].version).toBe('2.0.1');
+
+ // Assert: both snapshots created
+ expect(fileExists(dir, '.contractual/snapshots/orders-api.json')).toBe(true);
+ expect(fileExists(dir, '.contractual/snapshots/users-api.json')).toBe(true);
+
+ // Assert: changelog has entries for both
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toContain('[orders-api] v1.1.0');
+ expect(changelog).toContain('[users-api] v2.0.1');
+ expect(changelog).toContain('Added bulk operations endpoint');
+ expect(changelog).toContain('Fixed validation message');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('skips contracts not found in config', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'existing-api',
+ type: 'json-schema',
+ path: 'schemas/existing.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/existing.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'existing-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create changeset referencing a non-existent contract
+ writeFile(
+ dir,
+ '.contractual/changesets/mixed-update.md',
+ `---
+"existing-api": minor
+"nonexistent-api": major
+---
+## existing-api
+- Updated existing API
+
+## nonexistent-api
+- This contract does not exist
+`
+ );
+
+ const result = run('version', dir);
+
+ // Assert: command succeeds (processes what it can)
+ expect(result.exitCode).toBe(0);
+
+ // Assert: existing contract was bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['existing-api'].version).toBe('1.1.0');
+
+ // Assert: nonexistent contract was not added to versions
+ expect(versions['nonexistent-api']).toBeUndefined();
+
+ // Assert: changeset was still consumed
+ const changesetFiles = listFiles(dir, '.contractual/changesets');
+ expect(changesetFiles).toHaveLength(0);
+
+ // Assert: changelog only contains the valid contract
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toContain('[existing-api] v1.1.0');
+ expect(changelog).toContain('Updated existing API');
+ // The nonexistent-api changes should NOT appear in changelog (no version bumped for it)
+ expect(changelog).not.toContain('[nonexistent-api]');
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/06-status.test.ts b/tests/e2e/06-status.test.ts
new file mode 100644
index 0000000..38c1ba2
--- /dev/null
+++ b/tests/e2e/06-status.test.ts
@@ -0,0 +1,250 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual status', () => {
+ test('shows current versions from versions.json', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-schema',
+ type: 'json-schema',
+ path: 'schemas/user.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Set up versions
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.2.3', released: '2026-01-15T10:00:00Z' },
+ 'user-schema': { version: '2.0.0', released: '2026-02-01T12:00:00Z' },
+ })
+ );
+
+ const result = run('status', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).toMatch(/1\.2\.3/);
+ expect(result.stdout).toMatch(/user-schema/);
+ expect(result.stdout).toMatch(/2\.0\.0/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows pending changesets', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Set up version
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a pending changeset
+ const changesetContent = `---
+"order-schema": minor
+---
+
+## order-schema
+
+- **[minor]** Added optional tracking_number field
+`;
+ writeFile(dir, '.contractual/changesets/friendly-tiger.md', changesetContent);
+
+ const result = run('status', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/pending/i);
+ expect(result.stdout).toMatch(/friendly-tiger\.md/);
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).toMatch(/minor/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows projected bumps based on pending changesets', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-schema',
+ type: 'json-schema',
+ path: 'schemas/user.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Set up versions
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.5.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a changeset with major bump for order-schema
+ const changesetContent = `---
+"order-schema": major
+"user-schema": patch
+---
+
+## order-schema
+
+- **[BREAKING]** Removed customer_email field
+
+## user-schema
+
+- **[patch]** Updated description
+`;
+ writeFile(dir, '.contractual/changesets/breaking-change.md', changesetContent);
+
+ const result = run('status', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should show projected version 2.0.0 for order-schema (major bump from 1.0.0)
+ expect(result.stdout).toMatch(/2\.0\.0/);
+ // Should show projected version 1.5.1 for user-schema (patch bump from 1.5.0)
+ expect(result.stdout).toMatch(/1\.5\.1/);
+ // Should indicate major and patch bumps
+ expect(result.stdout).toMatch(/major/i);
+ expect(result.stdout).toMatch(/patch/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles empty state (no versions, no changesets)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // versions.json is empty (created by setupRepoWithConfig)
+ const result = run('status', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should show 0.0.0 or unreleased
+ expect(result.stdout).toMatch(/0\.0\.0|unreleased/i);
+ // Should indicate no pending changesets
+ expect(result.stdout).toMatch(/no pending changeset/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('aggregates multiple changesets correctly (highest bump wins)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Set up version
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create multiple changesets - patch and minor for same contract
+ const patchChangeset = `---
+"order-schema": patch
+---
+
+Fixed typo in description
+`;
+ const minorChangeset = `---
+"order-schema": minor
+---
+
+Added optional field
+`;
+ writeFile(dir, '.contractual/changesets/fix-typo.md', patchChangeset);
+ writeFile(dir, '.contractual/changesets/add-field.md', minorChangeset);
+
+ const result = run('status', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should show 2 pending changesets
+ expect(result.stdout).toMatch(/2.*changeset/i);
+ // Should project to 1.1.0 (minor wins over patch)
+ expect(result.stdout).toMatch(/1\.1\.0/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('reports error when not initialized', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Don't run init or setupRepoWithConfig - no .contractual directory
+
+ const result = run('status', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ // Error message contains "No contractual.yaml found"
+ expect(result.stdout + result.stderr).toMatch(/contractual\.yaml|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/07-full-lifecycle.test.ts b/tests/e2e/07-full-lifecycle.test.ts
new file mode 100644
index 0000000..f7844a0
--- /dev/null
+++ b/tests/e2e/07-full-lifecycle.test.ts
@@ -0,0 +1,372 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ fileExists,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual full lifecycle', () => {
+ test('complete cycle: init -> first release -> changes -> changeset -> second release', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // ===== PHASE 1: Setup with a spec using setupRepoWithConfig =====
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // ===== PHASE 2: Create initial changeset manually, run version (1.0.0) =====
+ const initialChangeset = `---
+"order": major
+---
+
+## order
+
+- **[major]** Initial release of order schema
+`;
+ writeFile(dir, '.contractual/changesets/initial-release.md', initialChangeset);
+
+ // Run version to consume the changeset
+ const versionResult1 = run('version', dir);
+ expect(versionResult1.exitCode).toBe(0);
+ expect(versionResult1.stdout).toMatch(/1\.0\.0/);
+
+ // Verify versions.json was updated
+ const versions1 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions1['order']).toBeDefined();
+ expect(versions1['order'].version).toBe('1.0.0');
+
+ // Verify changeset was consumed
+ const changesetsAfterV1 = listFiles(dir, '.contractual/changesets');
+ expect(changesetsAfterV1.filter((f) => f.endsWith('.md'))).toHaveLength(0);
+
+ // Verify snapshot was created
+ expect(fileExists(dir, '.contractual/snapshots/order.json')).toBe(true);
+
+ // Verify CHANGELOG.md was created
+ expect(fileExists(dir, 'CHANGELOG.md')).toBe(true);
+ const changelog1 = readFile(dir, 'CHANGELOG.md');
+ expect(changelog1).toMatch(/1\.0\.0/);
+
+ // ===== PHASE 3: Make breaking change to spec =====
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ // ===== PHASE 4: Run changeset command (auto-detect) =====
+ const changesetResult = run('changeset', dir);
+ expect(changesetResult.exitCode).toBe(0);
+ expect(changesetResult.stdout).toMatch(/created changeset/i);
+
+ // Verify a changeset file was created
+ const changesetsAfterDetect = listFiles(dir, '.contractual/changesets');
+ const mdFiles = changesetsAfterDetect.filter((f) => f.endsWith('.md'));
+ expect(mdFiles.length).toBeGreaterThan(0);
+
+ // Verify the changeset contains major bump (breaking change)
+ const changesetFile = readFile(dir, `.contractual/changesets/${mdFiles[0]}`);
+ expect(changesetFile).toMatch(/major/i);
+
+ // ===== PHASE 5: Run status (shows projected bump) =====
+ const statusResult = run('status', dir);
+ expect(statusResult.exitCode).toBe(0);
+ expect(statusResult.stdout).toMatch(/1\.0\.0/); // Current version
+ expect(statusResult.stdout).toMatch(/2\.0\.0/); // Projected version
+ expect(statusResult.stdout).toMatch(/major/i);
+ expect(statusResult.stdout).toMatch(/pending/i);
+
+ // ===== PHASE 6: Run version (bumps to 2.0.0) =====
+ const versionResult2 = run('version', dir);
+ expect(versionResult2.exitCode).toBe(0);
+ expect(versionResult2.stdout).toMatch(/2\.0\.0/);
+
+ // Verify versions.json was updated
+ const versions2 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions2['order'].version).toBe('2.0.0');
+
+ // Verify CHANGELOG.md was updated
+ const changelog2 = readFile(dir, 'CHANGELOG.md');
+ expect(changelog2).toMatch(/2\.0\.0/);
+ expect(changelog2).toMatch(/1\.0\.0/); // Previous version still there
+
+ // ===== PHASE 7: Verify breaking shows no changes after version =====
+ const breakingResult = run('breaking', dir);
+ expect(breakingResult.exitCode).toBe(0);
+ expect(breakingResult.stdout).toMatch(/no.*change|no breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('multiple releases accumulate in changelog (1.0.0 -> 1.1.0 -> 1.1.1)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Setup initial state
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Create snapshot (simulating a previous version)
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ // ===== Release 1.0.0 =====
+ const release1Changeset = `---
+"order-schema": major
+---
+
+## order-schema
+
+- **[major]** Initial release
+`;
+ writeFile(dir, '.contractual/changesets/release-1.md', release1Changeset);
+
+ const version1 = run('version', dir);
+ expect(version1.exitCode).toBe(0);
+
+ const versions1 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions1['order-schema'].version).toBe('1.0.0');
+
+ // ===== Release 1.1.0 (minor bump - add optional field) =====
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+
+ // Auto-detect changes
+ const changeset2 = run('changeset', dir);
+ expect(changeset2.exitCode).toBe(0);
+
+ const version2 = run('version', dir);
+ expect(version2.exitCode).toBe(0);
+
+ const versions2 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions2['order-schema'].version).toBe('1.1.0');
+
+ // ===== Release 1.1.1 (patch bump - description change) =====
+ copyFixture(
+ 'json-schema/order-description-changed.json',
+ path.join(dir, 'schemas/order.json')
+ );
+
+ // Create manual patch changeset
+ const patchChangeset = `---
+"order-schema": patch
+---
+
+## order-schema
+
+- **[patch]** Updated description text
+`;
+ writeFile(dir, '.contractual/changesets/patch-desc.md', patchChangeset);
+
+ const version3 = run('version', dir);
+ expect(version3.exitCode).toBe(0);
+
+ const versions3 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions3['order-schema'].version).toBe('1.1.1');
+
+ // ===== Verify changelog has all three versions =====
+ const changelog = readFile(dir, 'CHANGELOG.md');
+ expect(changelog).toMatch(/1\.0\.0/);
+ expect(changelog).toMatch(/1\.1\.0/);
+ expect(changelog).toMatch(/1\.1\.1/);
+
+ // Verify order in changelog (newest first typically)
+ const v100Index = changelog.indexOf('1.0.0');
+ const v110Index = changelog.indexOf('1.1.0');
+ const v111Index = changelog.indexOf('1.1.1');
+
+ // Newest versions should appear first in changelog
+ expect(v111Index).toBeLessThan(v110Index);
+ expect(v110Index).toBeLessThan(v100Index);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles multiple contracts with independent versioning', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-schema',
+ type: 'json-schema',
+ path: 'schemas/user.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // ===== Release both contracts at 1.0.0 =====
+ const initialChangeset = `---
+"order-schema": major
+"user-schema": major
+---
+
+Initial release of both schemas
+`;
+ writeFile(dir, '.contractual/changesets/initial.md', initialChangeset);
+
+ const version1 = run('version', dir);
+ expect(version1.exitCode).toBe(0);
+
+ const versions1 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions1['order-schema'].version).toBe('1.0.0');
+ expect(versions1['user-schema'].version).toBe('1.0.0');
+
+ // ===== Bump only order-schema to 2.0.0 =====
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const orderChangeset = `---
+"order-schema": major
+---
+
+## order-schema
+
+- **[BREAKING]** Removed customer_email field
+`;
+ writeFile(dir, '.contractual/changesets/order-breaking.md', orderChangeset);
+
+ const version2 = run('version', dir);
+ expect(version2.exitCode).toBe(0);
+
+ const versions2 = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions2['order-schema'].version).toBe('2.0.0');
+ expect(versions2['user-schema'].version).toBe('1.0.0'); // Unchanged
+
+ // ===== Verify status shows correct versions =====
+ const status = run('status', dir);
+ expect(status.exitCode).toBe(0);
+ expect(status.stdout).toMatch(/order-schema/);
+ expect(status.stdout).toMatch(/2\.0\.0/);
+ expect(status.stdout).toMatch(/user-schema/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('version command with no changesets does nothing', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // No changesets - just run version
+ const result = run('version', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no pending|nothing to version/i);
+
+ // Version should remain unchanged
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('changeset command with no changes does nothing', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Create snapshot matching current spec
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Spec matches snapshot - no changes
+ const result = run('changeset', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no change/i);
+
+ // No changeset should be created
+ const changesets = listFiles(dir, '.contractual/changesets');
+ expect(changesets.filter((f) => f.endsWith('.md'))).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/08-multi-contract.test.ts b/tests/e2e/08-multi-contract.test.ts
new file mode 100644
index 0000000..da31b53
--- /dev/null
+++ b/tests/e2e/08-multi-contract.test.ts
@@ -0,0 +1,337 @@
+import { describe, test, expect, beforeAll, beforeEach, afterEach } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ fileExists,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('multi-contract scenarios', () => {
+ let tempRepo: { dir: string; cleanup: () => void };
+
+ beforeEach(() => {
+ tempRepo = createTempRepo();
+ });
+
+ afterEach(() => {
+ tempRepo.cleanup();
+ });
+
+ test('lint works with multiple contracts of different types', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ { name: 'petstore-api', type: 'openapi', path: 'specs/petstore.yaml' },
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // OpenAPI linter (Spectral) runs and finds errors in petstore fixture
+ // JSON Schema linter validates and passes for valid schemas
+ const result = run('lint --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1); // petstore has lint errors
+
+ const parsed = JSON.parse(result.stdout);
+ // All 3 contracts have results
+ expect(parsed.results).toHaveLength(3);
+ // petstore has errors, JSON schemas pass
+ const petstoreResult = parsed.results.find((r: { contract: string }) => r.contract === 'petstore-api');
+ expect(petstoreResult.errors.length).toBeGreaterThan(0);
+ });
+
+ test('breaking detects changes in multiple contracts', () => {
+ const { dir } = tempRepo;
+
+ // Use only json-schema contracts for reliable testing
+ // (openapi requires oasdiff binary which may not be available)
+ setupRepoWithConfig(dir, [
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ // Set up snapshots for json-schema contracts
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/user-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current specs: breaking change in order-schema, no change in user
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+ expect(parsed.results).toHaveLength(2);
+
+ // Find results by contract name
+ const orderResult = parsed.results.find(
+ (r: { contract: string }) => r.contract === 'order-schema'
+ );
+ const userResult = parsed.results.find(
+ (r: { contract: string }) => r.contract === 'user-schema'
+ );
+
+ expect(orderResult.summary.breaking).toBeGreaterThan(0);
+ expect(userResult.summary.breaking).toBe(0);
+ expect(userResult.summary.nonBreaking).toBe(0);
+ });
+
+ test('changeset includes all changed contracts', () => {
+ const { dir } = tempRepo;
+
+ // Use only json-schema contracts since openapi requires oasdiff binary
+ setupRepoWithConfig(dir, [
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ // Set up snapshots
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/user-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current specs with changes - only order-schema changed
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json')); // No change
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Check that changeset file was created
+ const changesetFiles = listFiles(dir, '.contractual/changesets').filter(f => f.endsWith('.md'));
+ expect(changesetFiles.length).toBeGreaterThan(0);
+
+ // Read the changeset file (markdown with YAML frontmatter)
+ const changesetPath = `.contractual/changesets/${changesetFiles[0]}`;
+ const changesetContent = readFile(dir, changesetPath);
+
+ // Changeset should include order-schema (which changed)
+ expect(changesetContent).toContain('order-schema');
+ // user-schema should not be included (no changes)
+ expect(changesetContent).not.toContain('user-schema');
+ });
+
+ test('version bumps multiple contracts independently', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ // Current specs
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Set up existing versions
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.5', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a changeset with different bump types - using markdown format with YAML frontmatter
+ const changesetId = `changeset-${Date.now()}`;
+ writeFile(
+ dir,
+ `.contractual/changesets/${changesetId}.md`,
+ `---
+"order-schema": major
+"user-schema": patch
+---
+
+Multiple contracts bumped independently
+`
+ );
+
+ // Run version command
+ const result = run('version', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Check versions were bumped correctly
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+
+ expect(versions['order-schema'].version).toBe('3.0.0'); // major bump: 2.0.0 -> 3.0.0
+ expect(versions['user-schema'].version).toBe('1.0.6'); // patch bump: 1.0.5 -> 1.0.6
+
+ // Verify snapshots were updated
+ expect(fileExists(dir, '.contractual/snapshots/order-schema.json')).toBe(true);
+ expect(fileExists(dir, '.contractual/snapshots/user-schema.json')).toBe(true);
+
+ // Changeset should be consumed (removed)
+ expect(fileExists(dir, `.contractual/changesets/${changesetId}.md`)).toBe(false);
+ });
+
+ test('lint reports errors for invalid specs', () => {
+ const { dir } = tempRepo;
+
+ // Use lint: false for OpenAPI to avoid petstore errors, focus on JSON Schema validation
+ setupRepoWithConfig(dir, [
+ { name: 'valid-api', type: 'openapi', path: 'specs/valid.yaml', lint: false },
+ { name: 'invalid-schema', type: 'json-schema', path: 'schemas/invalid.json' },
+ { name: 'another-valid', type: 'json-schema', path: 'schemas/valid.json' },
+ ]);
+
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/valid.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/valid.json'));
+ // Write invalid JSON Schema
+ writeFile(
+ dir,
+ 'schemas/invalid.json',
+ JSON.stringify({
+ type: 'objekt', // Invalid type value
+ properties: {
+ id: { type: 123 }, // type should be string
+ },
+ })
+ );
+
+ // JSON Schema linter finds errors in invalid-schema, so exit code is 1
+ const result = run('lint --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ const parsed = JSON.parse(result.stdout);
+ // Should have 2 results (JSON Schema contracts only, OpenAPI has lint: false)
+ expect(parsed.results).toHaveLength(2);
+ // invalid-schema should have errors
+ const invalidResult = parsed.results.find((r: { contract: string }) => r.contract === 'invalid-schema');
+ expect(invalidResult.errors.length).toBeGreaterThan(0);
+ });
+
+ test('breaking --contract filters to single contract in multi-contract repo', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ { name: 'petstore-api', type: 'openapi', path: 'specs/petstore.yaml' },
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ ]);
+
+ // Set up snapshots
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore-api.yaml')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'petstore-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Both have breaking changes
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ // Filter to only check order-schema
+ const result = run('breaking --contract order-schema --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.results).toHaveLength(1);
+ expect(parsed.results[0].contract).toBe('order-schema');
+ expect(parsed.results[0].summary.breaking).toBeGreaterThan(0);
+ });
+
+ test('status shows all contracts with their current versions', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ { name: 'petstore-api', type: 'openapi', path: 'specs/petstore.yaml' },
+ { name: 'order-schema', type: 'json-schema', path: 'schemas/order.json' },
+ { name: 'user-schema', type: 'json-schema', path: 'schemas/user.json' },
+ ]);
+
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'petstore-api': { version: '1.2.0', released: '2026-01-01T00:00:00Z' },
+ 'order-schema': { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.5', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Status command only outputs text format (no --format json option)
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Check for text output containing contract info
+ expect(result.stdout).toMatch(/petstore-api/);
+ expect(result.stdout).toMatch(/openapi/);
+ expect(result.stdout).toMatch(/1\.2\.0/);
+
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).toMatch(/json-schema/);
+ expect(result.stdout).toMatch(/2\.0\.0/);
+
+ expect(result.stdout).toMatch(/user-schema/);
+ expect(result.stdout).toMatch(/1\.0\.5/);
+ });
+});
diff --git a/tests/e2e/09-differs.json-schema.test.ts b/tests/e2e/09-differs.json-schema.test.ts
new file mode 100644
index 0000000..c0a2de1
--- /dev/null
+++ b/tests/e2e/09-differs.json-schema.test.ts
@@ -0,0 +1,756 @@
+import { describe, test, expect, beforeAll, beforeEach, afterEach } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+interface BreakingChange {
+ category: string;
+ severity: string;
+ path: string;
+ message: string;
+}
+
+interface BreakingResult {
+ contract: string;
+ changes: BreakingChange[];
+ summary: {
+ breaking: number;
+ nonBreaking: number;
+ patch: number;
+ };
+}
+
+interface BreakingOutput {
+ hasBreaking: boolean;
+ results: BreakingResult[];
+}
+
+describe('JSON Schema differ exhaustive tests', () => {
+ let tempRepo: { dir: string; cleanup: () => void };
+
+ beforeEach(() => {
+ tempRepo = createTempRepo();
+ });
+
+ afterEach(() => {
+ tempRepo.cleanup();
+ });
+
+ /**
+ * Helper to set up a JSON Schema diff test scenario
+ */
+ function setupJsonSchemaDiff(baseFixture: string, currentFixture: string): void {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Set up base as snapshot (previous release)
+ copyFixture(baseFixture, path.join(dir, '.contractual/snapshots/order-schema.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Set up current spec
+ copyFixture(currentFixture, path.join(dir, 'schemas/order.json'));
+ }
+
+ describe('breaking changes (exit 1, major)', () => {
+ test('field removed -> category: property-removed', () => {
+ setupJsonSchemaDiff('json-schema/order-base.json', 'json-schema/order-field-removed.json');
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const propertyRemovedChange = changes.find((c) => c.category === 'property-removed');
+ expect(propertyRemovedChange).toBeDefined();
+ expect(propertyRemovedChange!.severity).toBe('breaking');
+ expect(propertyRemovedChange!.path).toContain('customer_email');
+ });
+
+ test('required added -> category: required-added', () => {
+ setupJsonSchemaDiff('json-schema/order-base.json', 'json-schema/order-required-added.json');
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const requiredAddedChange = changes.find((c) => c.category === 'required-added');
+ expect(requiredAddedChange).toBeDefined();
+ expect(requiredAddedChange!.severity).toBe('breaking');
+ // The path is /required, but the field name appears in the message
+ expect(requiredAddedChange!.path).toBe('/required');
+ expect(requiredAddedChange!.message).toContain('customer_email');
+ });
+
+ test('type changed -> category: type-changed', () => {
+ setupJsonSchemaDiff('json-schema/order-base.json', 'json-schema/order-type-changed.json');
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const typeChangedChange = changes.find((c) => c.category === 'type-changed');
+ expect(typeChangedChange).toBeDefined();
+ expect(typeChangedChange!.severity).toBe('breaking');
+ expect(typeChangedChange!.path).toContain('amount');
+ expect(typeChangedChange!.message).toMatch(/string.*number|type/i);
+ });
+
+ test('enum value removed -> category: enum-value-removed', () => {
+ setupJsonSchemaDiff(
+ 'json-schema/order-base.json',
+ 'json-schema/order-enum-value-removed.json'
+ );
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const enumRemovedChange = changes.find((c) => c.category === 'enum-value-removed');
+ expect(enumRemovedChange).toBeDefined();
+ expect(enumRemovedChange!.severity).toBe('breaking');
+ expect(enumRemovedChange!.path).toContain('status');
+ expect(enumRemovedChange!.message).toMatch(/delivered/i);
+ });
+
+ test('constraint tightened -> category: constraint-tightened', () => {
+ setupJsonSchemaDiff(
+ 'json-schema/order-base.json',
+ 'json-schema/order-constraint-tightened.json'
+ );
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const constraintChange = changes.find((c) => c.category === 'constraint-tightened');
+ expect(constraintChange).toBeDefined();
+ expect(constraintChange!.severity).toBe('breaking');
+ // Should detect maxLength reduction in zip (10 -> 5) or notes (500 -> 200)
+ expect(constraintChange!.message).toMatch(/maxLength|constraint/i);
+ });
+
+ test('additionalProperties denied -> category: additional-properties-denied', () => {
+ setupJsonSchemaDiff(
+ 'json-schema/order-base.json',
+ 'json-schema/order-additional-props-denied.json'
+ );
+
+ const result = run('breaking --format json', tempRepo.dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const additionalPropsChange = changes.find(
+ (c) => c.category === 'additional-properties-denied'
+ );
+ expect(additionalPropsChange).toBeDefined();
+ expect(additionalPropsChange!.severity).toBe('breaking');
+ expect(additionalPropsChange!.path).toContain('metadata');
+ });
+ });
+
+ describe('non-breaking changes (exit 0, minor)', () => {
+ test('optional field added -> category: property-added, severity: non-breaking', () => {
+ setupJsonSchemaDiff(
+ 'json-schema/order-base.json',
+ 'json-schema/order-optional-field-added.json'
+ );
+
+ const result = run('breaking --format json', tempRepo.dir);
+ expect(result.exitCode).toBe(0);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(false);
+
+ const changes = parsed.results[0].changes;
+ const propertyAddedChange = changes.find((c) => c.category === 'property-added');
+ expect(propertyAddedChange).toBeDefined();
+ expect(propertyAddedChange!.severity).toBe('non-breaking');
+ expect(propertyAddedChange!.path).toContain('tracking_number');
+
+ // Summary should show non-breaking changes
+ expect(parsed.results[0].summary.nonBreaking).toBeGreaterThan(0);
+ expect(parsed.results[0].summary.breaking).toBe(0);
+ });
+
+ test('enum value added -> category: enum-value-added', () => {
+ setupJsonSchemaDiff('json-schema/order-base.json', 'json-schema/order-enum-value-added.json');
+
+ const result = run('breaking --format json', tempRepo.dir);
+ expect(result.exitCode).toBe(0);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(false);
+
+ const changes = parsed.results[0].changes;
+ const enumAddedChange = changes.find((c) => c.category === 'enum-value-added');
+ expect(enumAddedChange).toBeDefined();
+ expect(enumAddedChange!.severity).toBe('non-breaking');
+ expect(enumAddedChange!.path).toContain('status');
+ expect(enumAddedChange!.message).toMatch(/cancelled/i);
+ });
+ });
+
+ describe('patch changes (exit 0, patch)', () => {
+ test('description changed -> category: description-changed', () => {
+ setupJsonSchemaDiff(
+ 'json-schema/order-base.json',
+ 'json-schema/order-description-changed.json'
+ );
+
+ const result = run('breaking --format json', tempRepo.dir);
+ expect(result.exitCode).toBe(0);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(false);
+
+ const changes = parsed.results[0].changes;
+ const descriptionChange = changes.find((c) => c.category === 'description-changed');
+ expect(descriptionChange).toBeDefined();
+ expect(descriptionChange!.severity).toBe('patch');
+
+ // Summary should show patch changes
+ expect(parsed.results[0].summary.patch).toBeGreaterThan(0);
+ expect(parsed.results[0].summary.breaking).toBe(0);
+ });
+ });
+
+ describe('no changes', () => {
+ test('identical schema -> no changes detected', () => {
+ setupJsonSchemaDiff('json-schema/order-base.json', 'json-schema/order-identical.json');
+
+ const result = run('breaking --format json', tempRepo.dir);
+ expect(result.exitCode).toBe(0);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(false);
+ expect(parsed.results[0].changes).toHaveLength(0);
+ expect(parsed.results[0].summary.breaking).toBe(0);
+ expect(parsed.results[0].summary.nonBreaking).toBe(0);
+ expect(parsed.results[0].summary.patch).toBe(0);
+ });
+ });
+
+ describe('multiple changes in single diff', () => {
+ test('detects multiple breaking changes in one schema update', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Use base as snapshot
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a schema with multiple breaking changes
+ const multiBreakingSchema = {
+ $schema: 'http://json-schema.org/draft-07/schema#',
+ $id: 'https://example.com/order.schema.json',
+ title: 'Order',
+ description: 'An order in the system',
+ type: 'object',
+ properties: {
+ id: {
+ type: 'number', // Type changed from string
+ description: 'Unique order identifier',
+ },
+ status: {
+ type: 'string',
+ enum: ['pending', 'processing'], // Removed 'shipped' and 'delivered'
+ description: 'Current order status',
+ },
+ // 'amount' property removed
+ currency: {
+ type: 'string',
+ format: 'iso-4217',
+ description: 'Currency code (ISO 4217)',
+ },
+ items: {
+ type: 'array',
+ description: 'Line items in the order',
+ items: {
+ type: 'object',
+ properties: {
+ sku: { type: 'string' },
+ quantity: { type: 'integer', minimum: 1 },
+ price: { type: 'string' },
+ },
+ required: ['sku', 'quantity', 'price'],
+ },
+ },
+ created_at: {
+ type: 'string',
+ format: 'date-time',
+ description: 'Order creation timestamp',
+ },
+ },
+ required: ['id', 'status', 'currency', 'items', 'created_at', 'customer_email'], // Added required field
+ additionalProperties: false,
+ };
+
+ writeFile(dir, 'schemas/order.json', JSON.stringify(multiBreakingSchema, null, 2));
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const breakingChanges = changes.filter((c) => c.severity === 'breaking');
+
+ // Should detect multiple breaking changes
+ expect(breakingChanges.length).toBeGreaterThanOrEqual(2);
+
+ // Check for specific categories
+ const categories = breakingChanges.map((c) => c.category);
+ expect(categories).toContain('type-changed');
+ expect(
+ categories.includes('enum-value-removed') || categories.includes('property-removed')
+ ).toBe(true);
+ });
+
+ test('detects mix of breaking and non-breaking changes', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create a schema with both breaking and non-breaking changes
+ const mixedChangesSchema = {
+ $schema: 'http://json-schema.org/draft-07/schema#',
+ $id: 'https://example.com/order.schema.json',
+ title: 'Order',
+ description: 'An order in the e-commerce system', // Description changed (patch)
+ type: 'object',
+ properties: {
+ id: {
+ type: 'number', // Type changed (breaking)
+ description: 'Unique order identifier',
+ },
+ status: {
+ type: 'string',
+ enum: ['pending', 'processing', 'shipped', 'delivered', 'cancelled'], // Added enum value (non-breaking)
+ description: 'Current order status',
+ },
+ amount: {
+ type: 'string',
+ description: 'Order total amount as string',
+ },
+ currency: {
+ type: 'string',
+ format: 'iso-4217',
+ description: 'Currency code (ISO 4217)',
+ },
+ items: {
+ type: 'array',
+ description: 'Line items in the order',
+ items: {
+ type: 'object',
+ properties: {
+ sku: { type: 'string' },
+ quantity: { type: 'integer', minimum: 1 },
+ price: { type: 'string' },
+ },
+ required: ['sku', 'quantity', 'price'],
+ },
+ },
+ shipping_address: {
+ type: 'object',
+ description: 'Shipping address',
+ properties: {
+ street: { type: 'string' },
+ city: { type: 'string' },
+ zip: { type: 'string', maxLength: 10 },
+ country: { type: 'string' },
+ },
+ required: ['street', 'city', 'zip', 'country'],
+ },
+ customer_email: {
+ type: 'string',
+ format: 'email',
+ description: 'Customer email address',
+ },
+ notes: {
+ type: 'string',
+ description: 'Optional order notes',
+ maxLength: 500,
+ },
+ created_at: {
+ type: 'string',
+ format: 'date-time',
+ description: 'Order creation timestamp',
+ },
+ metadata: {
+ type: 'object',
+ description: 'Additional metadata',
+ additionalProperties: true,
+ },
+ tracking_number: {
+ // New optional property (non-breaking)
+ type: 'string',
+ description: 'Shipment tracking number',
+ },
+ },
+ required: ['id', 'status', 'amount', 'currency', 'items', 'created_at'],
+ additionalProperties: false,
+ };
+
+ writeFile(dir, 'schemas/order.json', JSON.stringify(mixedChangesSchema, null, 2));
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1); // Exit 1 because there are breaking changes
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const { summary } = parsed.results[0];
+ expect(summary.breaking).toBeGreaterThan(0);
+ expect(summary.nonBreaking).toBeGreaterThan(0);
+ });
+ });
+
+ describe('nested property changes', () => {
+ test('detects changes in nested object properties', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create schema with nested property changes (shipping_address.zip maxLength changed)
+ const nestedChangeSchema = {
+ $schema: 'http://json-schema.org/draft-07/schema#',
+ $id: 'https://example.com/order.schema.json',
+ title: 'Order',
+ description: 'An order in the system',
+ type: 'object',
+ properties: {
+ id: { type: 'string', description: 'Unique order identifier' },
+ status: {
+ type: 'string',
+ enum: ['pending', 'processing', 'shipped', 'delivered'],
+ description: 'Current order status',
+ },
+ amount: { type: 'string', description: 'Order total amount as string' },
+ currency: {
+ type: 'string',
+ format: 'iso-4217',
+ description: 'Currency code (ISO 4217)',
+ },
+ items: {
+ type: 'array',
+ description: 'Line items in the order',
+ items: {
+ type: 'object',
+ properties: {
+ sku: { type: 'string' },
+ quantity: { type: 'integer', minimum: 1 },
+ price: { type: 'string' },
+ },
+ required: ['sku', 'quantity', 'price'],
+ },
+ },
+ shipping_address: {
+ type: 'object',
+ description: 'Shipping address',
+ properties: {
+ street: { type: 'string' },
+ city: { type: 'string' },
+ zip: { type: 'string', maxLength: 5 }, // Changed from 10 to 5 (breaking)
+ country: { type: 'string' },
+ },
+ required: ['street', 'city', 'zip', 'country'],
+ },
+ customer_email: {
+ type: 'string',
+ format: 'email',
+ description: 'Customer email address',
+ },
+ notes: { type: 'string', description: 'Optional order notes', maxLength: 500 },
+ created_at: {
+ type: 'string',
+ format: 'date-time',
+ description: 'Order creation timestamp',
+ },
+ metadata: {
+ type: 'object',
+ description: 'Additional metadata',
+ additionalProperties: true,
+ },
+ },
+ required: ['id', 'status', 'amount', 'currency', 'items', 'created_at'],
+ additionalProperties: false,
+ };
+
+ writeFile(dir, 'schemas/order.json', JSON.stringify(nestedChangeSchema, null, 2));
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const constraintChange = changes.find((c) => c.category === 'constraint-tightened');
+ expect(constraintChange).toBeDefined();
+ expect(constraintChange!.path).toContain('shipping_address');
+ expect(constraintChange!.path).toContain('zip');
+ });
+
+ test('detects changes in array item schema', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create schema with array item changes (items[].sku type changed)
+ const arrayItemChangeSchema = {
+ $schema: 'http://json-schema.org/draft-07/schema#',
+ $id: 'https://example.com/order.schema.json',
+ title: 'Order',
+ description: 'An order in the system',
+ type: 'object',
+ properties: {
+ id: { type: 'string', description: 'Unique order identifier' },
+ status: {
+ type: 'string',
+ enum: ['pending', 'processing', 'shipped', 'delivered'],
+ description: 'Current order status',
+ },
+ amount: { type: 'string', description: 'Order total amount as string' },
+ currency: {
+ type: 'string',
+ format: 'iso-4217',
+ description: 'Currency code (ISO 4217)',
+ },
+ items: {
+ type: 'array',
+ description: 'Line items in the order',
+ items: {
+ type: 'object',
+ properties: {
+ sku: { type: 'number' }, // Changed from string to number (breaking)
+ quantity: { type: 'integer', minimum: 1 },
+ price: { type: 'string' },
+ },
+ required: ['sku', 'quantity', 'price'],
+ },
+ },
+ shipping_address: {
+ type: 'object',
+ description: 'Shipping address',
+ properties: {
+ street: { type: 'string' },
+ city: { type: 'string' },
+ zip: { type: 'string', maxLength: 10 },
+ country: { type: 'string' },
+ },
+ required: ['street', 'city', 'zip', 'country'],
+ },
+ customer_email: {
+ type: 'string',
+ format: 'email',
+ description: 'Customer email address',
+ },
+ notes: { type: 'string', description: 'Optional order notes', maxLength: 500 },
+ created_at: {
+ type: 'string',
+ format: 'date-time',
+ description: 'Order creation timestamp',
+ },
+ metadata: {
+ type: 'object',
+ description: 'Additional metadata',
+ additionalProperties: true,
+ },
+ },
+ required: ['id', 'status', 'amount', 'currency', 'items', 'created_at'],
+ additionalProperties: false,
+ };
+
+ writeFile(dir, 'schemas/order.json', JSON.stringify(arrayItemChangeSchema, null, 2));
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+
+ const parsed: BreakingOutput = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(true);
+
+ const changes = parsed.results[0].changes;
+ const typeChange = changes.find((c) => c.category === 'type-changed');
+ expect(typeChange).toBeDefined();
+ expect(typeChange!.path).toContain('items');
+ expect(typeChange!.path).toContain('sku');
+ });
+ });
+
+ describe('edge cases', () => {
+ test('handles first version (no snapshot)', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // No snapshot exists - first version
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('breaking --format json', dir);
+ expect(result.exitCode).toBe(0);
+
+ const parsed = JSON.parse(result.stdout);
+ expect(parsed.hasBreaking).toBe(false);
+ // First version with no snapshot shows the contract with no changes
+ if (parsed.results.length > 0) {
+ expect(parsed.results[0].changes).toHaveLength(0);
+ }
+ });
+
+ test('handles contract with breaking detection disabled', () => {
+ const { dir } = tempRepo;
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ breaking: false,
+ },
+ ]);
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Even with breaking changes, should pass because breaking detection is disabled
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ // When breaking detection is disabled, shows "No changes detected"
+ expect(result.stdout).toMatch(/no changes detected/i);
+ });
+ });
+});
diff --git a/tests/e2e/10-openapi-differ.test.ts b/tests/e2e/10-openapi-differ.test.ts
new file mode 100644
index 0000000..984ec81
--- /dev/null
+++ b/tests/e2e/10-openapi-differ.test.ts
@@ -0,0 +1,247 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('OpenAPI differ (native)', () => {
+ test('detects breaking change when endpoint is removed', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot (simulating previous release)
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec has endpoint removed (breaking change)
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects non-breaking change when endpoint is added', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec has new endpoint added (non-breaking change)
+ copyFixture(
+ 'openapi/petstore-nonbreaking-endpoint-added.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ // Non-breaking changes should exit 0
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/non-breaking|minor|no breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('reports no changes when specs are identical', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec is identical to snapshot
+ copyFixture('openapi/petstore-identical.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no.*change|no breaking|identical/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects breaking change when response type is changed', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec has type change (breaking)
+ copyFixture(
+ 'openapi/petstore-breaking-type-changed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects non-breaking change when only description is updated', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec has only description changed (non-breaking)
+ copyFixture(
+ 'openapi/petstore-nonbreaking-description.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('returns JSON output with --format json flag', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ // Set up base spec as snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec has breaking change
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ const parsed = JSON.parse(result.stdout);
+
+ expect(parsed).toHaveProperty('results');
+ expect(parsed).toHaveProperty('hasBreaking');
+ expect(parsed.hasBreaking).toBe(true);
+ expect(Array.isArray(parsed.results)).toBe(true);
+ expect(parsed.results.length).toBeGreaterThan(0);
+ expect(parsed.results[0]).toHaveProperty('contract', 'petstore');
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/11-custom-commands.test.ts b/tests/e2e/11-custom-commands.test.ts
new file mode 100644
index 0000000..8edeb72
--- /dev/null
+++ b/tests/e2e/11-custom-commands.test.ts
@@ -0,0 +1,330 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ fileExists,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('custom command overrides', () => {
+ describe('custom lint command', () => {
+ test('uses custom lint command with {spec} placeholder', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create a custom lint script that creates a marker file
+ writeFile(
+ dir,
+ 'custom-lint.sh',
+ `#!/bin/bash
+echo "Custom lint executed for: $1"
+touch "${dir}/lint-marker.txt"
+exit 0
+`
+ );
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: `bash ${dir}/custom-lint.sh {spec}`,
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ // Custom command was executed - marker file should exist
+ expect(fileExists(dir, 'lint-marker.txt')).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('custom lint command without {spec} uses default linter', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // A lint override that doesn't contain {spec} falls through to default linter
+ // The petstore fixture has lint errors, so the default linter will exit 1
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: 'exit 1', // No {spec} - falls through to default linter
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Default OpenAPI linter runs and finds errors in the petstore fixture
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ // Should show lint errors from the default linter
+ expect(result.stdout).toMatch(/error/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint: false disables linting for contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: false,
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ // Spinner output goes to TTY, not captured in stdout
+ // JSON format shows empty results when linting is disabled
+ const jsonResult = run('lint --format json', dir);
+ const parsed = JSON.parse(jsonResult.stdout);
+ expect(parsed.results).toHaveLength(0);
+ expect(parsed.errors).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lint: false with invalid spec still passes (linting skipped)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'bad-spec',
+ type: 'openapi',
+ path: 'specs/bad.yaml',
+ lint: false,
+ },
+ ]);
+ // Write intentionally invalid OpenAPI
+ writeFile(
+ dir,
+ 'specs/bad.yaml',
+ `openapi: 3.0.0
+info:
+ title: Invalid
+ # Missing version field - normally invalid
+paths: [] # paths should be object, not array
+`
+ );
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ // Verify via JSON that the contract was skipped (not in results)
+ const jsonResult = run('lint --format json', dir);
+ const parsed = JSON.parse(jsonResult.stdout);
+ expect(parsed.results).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('custom breaking command', () => {
+ test('uses custom breaking command with {old} and {new} placeholders', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create a custom breaking detection script
+ writeFile(
+ dir,
+ 'custom-breaking.sh',
+ `#!/bin/bash
+echo "Comparing old: $1 with new: $2"
+touch "${dir}/breaking-marker.txt"
+exit 0
+`
+ );
+
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ breaking: `bash ${dir}/custom-breaking.sh {old} {new}`,
+ },
+ ]);
+
+ // Set up snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Current spec with changes
+ copyFixture(
+ 'openapi/petstore-nonbreaking-endpoint-added.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ // Custom command was executed - marker file should exist
+ expect(fileExists(dir, 'breaking-marker.txt')).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('custom breaking command without placeholders uses default differ', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Custom command without {old} or {new} falls through to default differ
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ breaking: 'echo "Breaking change detected" && exit 1',
+ },
+ ]);
+
+ // Set up snapshot
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ // Same spec as snapshot - no changes, default differ will pass
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Default differ runs - with identical specs, should pass (no breaking changes)
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking: false disables breaking detection for contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ breaking: false,
+ },
+ ]);
+
+ // Set up snapshot with breaking change in current
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ // Even with a breaking change, it should pass because breaking detection is disabled
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ // When breaking detection is disabled, shows "No changes detected"
+ expect(result.stdout).toMatch(/no changes detected/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('mixed custom and default commands', () => {
+ test('can mix custom lint with default breaking', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Custom lint command with {spec} - will be executed
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: 'echo "Custom lint for {spec}" && exit 0',
+ // No custom breaking - uses default
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Custom lint command with {spec} runs and exits 0
+ const lintResult = run('lint', dir);
+ expect(lintResult.exitCode).toBe(0);
+
+ // Default breaking (no snapshot) - exits 0
+ const breakingResult = run('breaking', dir);
+ expect(breakingResult.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('can have different settings per contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api-v1',
+ type: 'openapi',
+ path: 'specs/api-v1.yaml',
+ lint: false, // Disable lint for v1
+ breaking: false, // Disable breaking for v1
+ },
+ {
+ name: 'api-v2',
+ type: 'openapi',
+ path: 'specs/api-v2.yaml',
+ // Use defaults for v2 - will use default OpenAPI linter
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api-v1.yaml'));
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api-v2.yaml'));
+
+ // The petstore fixture has lint errors, so api-v2 will cause exit 1
+ const result = run('lint --format json', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ const parsed = JSON.parse(result.stdout);
+
+ // api-v1 is skipped (lint: false), api-v2 is linted with default linter
+ expect(parsed.results).toHaveLength(1);
+ expect(parsed.results[0].contract).toBe('api-v2');
+ // api-v2 has lint errors from the petstore fixture
+ expect(parsed.errors).toBeGreaterThan(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/11-openapi-31-differ.test.ts b/tests/e2e/11-openapi-31-differ.test.ts
new file mode 100644
index 0000000..7b9c241
--- /dev/null
+++ b/tests/e2e/11-openapi-31-differ.test.ts
@@ -0,0 +1,204 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('OpenAPI 3.1 differ', () => {
+ test('detects breaking change when endpoint is removed (3.1 spec)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ copyFixture(
+ 'openapi/petstore-31-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects breaking change when type is narrowed (3.1 type arrays)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // tag field narrowed from ["string", "null"] to "string"
+ copyFixture(
+ 'openapi/petstore-31-breaking-type-narrowed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects non-breaking change when type is widened (3.1 type arrays)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // id field widened from integer to [integer, string]
+ copyFixture(
+ 'openapi/petstore-31-nonbreaking-type-widened.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('reports no changes when 3.1 specs are identical', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Same spec as snapshot
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no.*change|no breaking|identical/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('returns JSON output for 3.1 spec with --format json', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ copyFixture(
+ 'openapi/petstore-31-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking --format json', dir, { expectFail: true });
+ const parsed = JSON.parse(result.stdout);
+
+ expect(parsed).toHaveProperty('results');
+ expect(parsed).toHaveProperty('hasBreaking');
+ expect(parsed.hasBreaking).toBe(true);
+ expect(Array.isArray(parsed.results)).toBe(true);
+ expect(parsed.results.length).toBeGreaterThan(0);
+ expect(parsed.results[0]).toHaveProperty('contract', 'petstore');
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/12-edge-cases.test.ts b/tests/e2e/12-edge-cases.test.ts
new file mode 100644
index 0000000..b4eeda0
--- /dev/null
+++ b/tests/e2e/12-edge-cases.test.ts
@@ -0,0 +1,507 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('error handling and edge cases', () => {
+ describe('missing contractual.yaml', () => {
+ test('exits with error suggesting init when no config exists', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Run lint without any config
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/contractual\.yaml|not found|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking command suggests init when no config exists', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/contractual\.yaml|not found|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('status command suggests init when no config exists', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ const result = run('status', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/contractual\.yaml|not found|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('invalid YAML configuration', () => {
+ test('exits with parse error for malformed YAML', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write invalid YAML syntax
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ - name: broken
+ type: [this is invalid yaml
+ path: nowhere
+`
+ );
+
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/parse|yaml|syntax|invalid/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('exits with error for invalid config structure', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write valid YAML but invalid config structure
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts: "this should be an array"
+`
+ );
+
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/invalid|error|array/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles empty config file gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ writeFile(dir, 'contractual.yaml', '');
+
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/empty|invalid|error/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('spec file not found', () => {
+ test('lint reports error when spec file does not exist', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'missing-api',
+ type: 'openapi',
+ path: 'specs/nonexistent.yaml',
+ },
+ ]);
+
+ // Config loader warns about missing files but continues
+ // Linter will fail when trying to read the missing file
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/warning|not found|no such file|ENOENT/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking command handles missing spec file gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'missing-api',
+ type: 'openapi',
+ path: 'specs/nonexistent.yaml',
+ },
+ ]);
+ // Set up snapshot but no current spec
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/missing-api.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'missing-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Config loader warns about missing file but continues
+ // Breaking command may fail during diff (if oasdiff available) or report no differ
+ const result = run('breaking', dir, { expectFail: true });
+ // Should mention the missing file or failed check in output
+ expect(result.stdout + result.stderr).toMatch(/warning|not found|failed|error|no contracts/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('lints valid contracts and reports error for missing spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'valid-api',
+ type: 'openapi',
+ path: 'specs/valid.yaml',
+ },
+ {
+ name: 'missing-api',
+ type: 'openapi',
+ path: 'specs/nonexistent.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/valid.yaml'));
+
+ // Config loader emits a warning about missing files but continues
+ // Lint will process valid contract and fail on missing one
+ const result = run('lint', dir, { expectFail: true });
+ // Should mention the missing file
+ expect(result.stdout + result.stderr).toMatch(/nonexistent|not found|ENOENT/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('corrupt versions.json', () => {
+ test('status handles corrupt/invalid JSON in versions.json gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Write corrupt JSON to versions.json
+ writeFile(dir, '.contractual/versions.json', '{ this is not valid json }}}');
+
+ // The readVersions function in status.command.ts returns {} on parse error
+ // So the status command should succeed, treating all contracts as unreleased
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/unreleased|0\.0\.0/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('status handles versions.json with wrong structure gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Write valid JSON but wrong structure (array instead of object)
+ // This will be treated as invalid, and status will show contracts as unreleased
+ writeFile(dir, '.contractual/versions.json', JSON.stringify(['not', 'an', 'object']));
+
+ const result = run('status', dir);
+ // Status command should succeed - it may treat versions as empty
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking handles missing snapshot gracefully', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // No snapshot exists for this contract - first version
+ const result = run('breaking', dir);
+ // Should handle gracefully - exits with 0
+ expect(result.exitCode).toBe(0);
+ // When no snapshot exists, shows "No changes detected"
+ expect(result.stdout).toMatch(/no changes detected/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('changeset references unknown contract', () => {
+ test('status shows changeset referencing unknown contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Create a changeset that references an unknown contract
+ // Format: YAML frontmatter with "contract-name": bump-type
+ writeFile(
+ dir,
+ '.contractual/changesets/orphan-change.md',
+ `---
+"unknown-contract": minor
+---
+
+This references a contract that does not exist
+`
+ );
+
+ // Status command should succeed - it shows the changeset
+ // but the projected version won't be shown for an unknown contract
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+ // Should list the changeset
+ expect(result.stdout).toMatch(/changeset|pending/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('version command handles changeset with unknown contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Create a valid changeset for known contract
+ writeFile(
+ dir,
+ '.contractual/changesets/valid-change.md',
+ `---
+"petstore": patch
+---
+
+A valid change
+`
+ );
+
+ // Create a changeset for unknown contract
+ writeFile(
+ dir,
+ '.contractual/changesets/orphan-change.md',
+ `---
+"ghost-api": major
+---
+
+This references a non-existent contract
+`
+ );
+
+ const result = run('version', dir);
+ // Should process changesets - the unknown one will be in the aggregation
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('empty contracts array', () => {
+ test('lint rejects empty contracts array per schema validation', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, []);
+
+ // Empty contracts array is invalid per config schema (minItems: 1)
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/invalid|error|contract|minItems/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('breaking rejects empty contracts array per schema validation', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, []);
+
+ // Empty contracts array is invalid per config schema (minItems: 1)
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/invalid|error|contract|minItems/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('status rejects empty contracts array per schema validation', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, []);
+
+ // Empty contracts array is invalid per config schema (minItems: 1)
+ const result = run('status', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/invalid|error|contract|minItems/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('special characters in paths', () => {
+ test('handles spec path with spaces', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'spaced-api',
+ type: 'openapi',
+ path: 'specs/my api spec.yaml',
+ lint: false, // Disable linting to avoid errors from fixture spec
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/my api spec.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles contract name with dashes and numbers', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Contract names must match pattern: ^[a-z][a-z0-9-]*$
+ // So dashes and numbers are allowed, but not dots
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api-v2-beta',
+ type: 'openapi',
+ path: 'specs/api.yaml',
+ lint: false, // Disable linting to avoid errors from fixture spec
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('permission and file system errors', () => {
+ test('lint reports permission error when spec file is unreadable', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Make file unreadable (only works on Unix-like systems)
+ try {
+ require('node:fs').chmodSync(path.join(dir, 'specs/petstore.yaml'), 0o000);
+ } catch {
+ // Skip this test on systems where chmod doesn't work
+ return;
+ }
+
+ try {
+ // Linter will fail when trying to read the file
+ const result = run('lint', dir, { expectFail: true });
+ expect(result.exitCode).not.toBe(0);
+ expect(result.stdout + result.stderr).toMatch(/permission|EACCES|denied|error/i);
+ } finally {
+ // Restore permissions for cleanup
+ require('node:fs').chmodSync(path.join(dir, 'specs/petstore.yaml'), 0o644);
+ }
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('concurrent operations', () => {
+ test('handles being run in parallel (no race conditions)', async () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: false, // Disable linting to avoid errors from fixture spec
+ breaking: false, // Disable breaking to avoid needing snapshot
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Run multiple commands in parallel
+ // Note: status command does not have --format flag
+ const results = await Promise.all([
+ Promise.resolve(run('lint', dir)),
+ Promise.resolve(run('status', dir)),
+ Promise.resolve(run('breaking', dir)),
+ ]);
+
+ // All should succeed
+ for (const result of results) {
+ expect(result.exitCode).toBe(0);
+ }
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/12-openapi-circular-refs.test.ts b/tests/e2e/12-openapi-circular-refs.test.ts
new file mode 100644
index 0000000..fb94d65
--- /dev/null
+++ b/tests/e2e/12-openapi-circular-refs.test.ts
@@ -0,0 +1,91 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('OpenAPI differ with circular $ref schemas', () => {
+ test('handles identical specs with circular refs without stack overflow', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'circular-api',
+ type: 'openapi',
+ path: 'specs/api.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/circular-refs-base.yaml',
+ path.join(dir, '.contractual/snapshots/circular-api.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'circular-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Same spec β should produce no changes, not a stack overflow
+ copyFixture(
+ 'openapi/circular-refs-base.yaml',
+ path.join(dir, 'specs/api.yaml')
+ );
+
+ // 10s timeout β stack overflow would hang/crash without it
+ const result = run('breaking', dir, { timeout: 10_000 });
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no.*change|no breaking|identical/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('detects breaking change in schema with circular refs', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'circular-api',
+ type: 'openapi',
+ path: 'specs/api.yaml',
+ },
+ ]);
+
+ copyFixture(
+ 'openapi/circular-refs-base.yaml',
+ path.join(dir, '.contractual/snapshots/circular-api.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'circular-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Category.id changed from integer to string β breaking
+ copyFixture(
+ 'openapi/circular-refs-breaking.yaml',
+ path.join(dir, 'specs/api.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true, timeout: 10_000 });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/13-config-variations.test.ts b/tests/e2e/13-config-variations.test.ts
new file mode 100644
index 0000000..b091bb6
--- /dev/null
+++ b/tests/e2e/13-config-variations.test.ts
@@ -0,0 +1,448 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readYAML,
+ fileExists,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('config variations', () => {
+ test('minimal config (just contracts array) works', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write minimal config with only required fields
+ // Use lint: false to avoid petstore fixture lint errors
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: false
+`
+ );
+
+ // Create .contractual directory structure
+ writeFile(dir, '.contractual/versions.json', '{}');
+
+ // Copy the spec file
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ // Lint should work with minimal config (lint disabled)
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify config was parsed correctly
+ const config = readYAML(dir, 'contractual.yaml') as { contracts: Array<{ name: string; type: string; path: string }> };
+ expect(config.contracts).toHaveLength(1);
+ expect(config.contracts[0].name).toBe('api');
+ expect(config.contracts[0].type).toBe('openapi');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with changeset options (autoDetect, requireOnPR)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write config with changeset options
+ // Use lint: false to avoid petstore fixture lint errors
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: false
+changeset:
+ autoDetect: true
+ requireOnPR: false
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ // Config should be valid and lint should work
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify changeset options are preserved
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array;
+ changeset: { autoDetect: boolean; requireOnPR: boolean };
+ };
+ expect(config.changeset).toBeDefined();
+ expect(config.changeset.autoDetect).toBe(true);
+ expect(config.changeset.requireOnPR).toBe(false);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with AI options (disabled by default)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write config with AI options - all features disabled
+ // Use lint: false to avoid petstore fixture lint errors
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: false
+ai:
+ provider: anthropic
+ model: claude-3-sonnet
+ features:
+ explain: false
+ changelog: false
+ enhance: false
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ // Config should be valid
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify AI options are preserved
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array;
+ ai: {
+ provider: string;
+ model: string;
+ features: { explain: boolean; changelog: boolean; enhance: boolean };
+ };
+ };
+ expect(config.ai).toBeDefined();
+ expect(config.ai.provider).toBe('anthropic');
+ expect(config.ai.model).toBe('claude-3-sonnet');
+ expect(config.ai.features.explain).toBe(false);
+ expect(config.ai.features.changelog).toBe(false);
+ expect(config.ai.features.enhance).toBe(false);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('glob patterns in contract path work', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write config with glob pattern and lint disabled
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: all-schemas
+ type: json-schema
+ path: schemas/*.json
+ lint: false
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+
+ // Create multiple schema files matching the glob
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Lint should work with glob pattern (lint disabled)
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify the file exists at the expected location
+ expect(fileExists(dir, 'schemas/order.json')).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('contract with all optional fields specified', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write config with all optional contract fields
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: full-contract
+ type: openapi
+ path: specs/api.yaml
+ lint: spectral
+ breaking: oasdiff
+ generate:
+ - openapi-generator generate -i specs/api.yaml -g typescript-axios -o ./client
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ // Use status command to verify config is valid (lint would fail due to petstore fixture errors)
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify all optional fields are preserved
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{
+ name: string;
+ type: string;
+ path: string;
+ lint: string;
+ breaking: string;
+ generate: string[];
+ }>;
+ };
+ expect(config.contracts[0].lint).toBe('spectral');
+ expect(config.contracts[0].breaking).toBe('oasdiff');
+ expect(config.contracts[0].generate).toEqual([
+ 'openapi-generator generate -i specs/api.yaml -g typescript-axios -o ./client',
+ ]);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with multiple contract types and mixed options', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write complex config with multiple contracts and various options
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: spectral
+ - name: events
+ type: json-schema
+ path: schemas/events.json
+ lint: false
+ breaking: false
+changeset:
+ autoDetect: true
+ requireOnPR: true
+ai:
+ provider: anthropic
+ features:
+ explain: true
+ changelog: false
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/events.json'));
+
+ // Use status command to verify config is valid (lint would fail due to petstore fixture errors)
+ const result = run('status', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify config structure
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{ name: string; lint?: string | boolean; breaking?: string | boolean }>;
+ changeset: { autoDetect: boolean; requireOnPR: boolean };
+ ai: { provider: string; features: { explain: boolean; changelog: boolean } };
+ };
+ expect(config.contracts).toHaveLength(2);
+ expect(config.contracts[0].lint).toBe('spectral');
+ expect(config.contracts[1].lint).toBe(false);
+ expect(config.contracts[1].breaking).toBe(false);
+ expect(config.changeset.autoDetect).toBe(true);
+ expect(config.ai.features.explain).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with nested directory structure for specs', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Write config pointing to deeply nested spec, with lint disabled
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: nested-api
+ type: openapi
+ path: src/contracts/api/v1/openapi.yaml
+ lint: false
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, 'src/contracts/api/v1/openapi.yaml')
+ );
+
+ // Lint should work with nested paths (lint disabled)
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Verify nested file exists
+ expect(fileExists(dir, 'src/contracts/api/v1/openapi.yaml')).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with only changeset options (no ai)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: false
+changeset:
+ autoDetect: false
+ requireOnPR: true
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array;
+ changeset: { autoDetect: boolean; requireOnPR: boolean };
+ ai?: unknown;
+ };
+ expect(config.changeset.autoDetect).toBe(false);
+ expect(config.changeset.requireOnPR).toBe(true);
+ expect(config.ai).toBeUndefined();
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('config with only ai options (no changeset)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: api
+ type: openapi
+ path: specs/api.yaml
+ lint: false
+ai:
+ provider: anthropic
+ features:
+ explain: true
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/api.yaml'));
+
+ const result = run('lint', dir);
+ expect(result.exitCode).toBe(0);
+
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array;
+ ai: { provider: string; features: { explain: boolean } };
+ changeset?: unknown;
+ };
+ expect(config.ai.provider).toBe('anthropic');
+ expect(config.ai.features.explain).toBe(true);
+ expect(config.changeset).toBeUndefined();
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('asyncapi contract type is accepted', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: events
+ type: asyncapi
+ path: specs/events.yaml
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ // Use a basic YAML file as placeholder (asyncapi would have similar structure)
+ writeFile(
+ dir,
+ 'specs/events.yaml',
+ `asyncapi: 2.6.0
+info:
+ title: Events API
+ version: 1.0.0
+channels: {}
+`
+ );
+
+ // Config validation should pass (even if lint may not have asyncapi support yet)
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{ name: string; type: string }>;
+ };
+ expect(config.contracts[0].type).toBe('asyncapi');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('odcs contract type is accepted', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: data-contract
+ type: odcs
+ path: contracts/data.yaml
+`
+ );
+
+ writeFile(dir, '.contractual/versions.json', '{}');
+ // Use a basic YAML file as placeholder for ODCS
+ writeFile(
+ dir,
+ 'contracts/data.yaml',
+ `dataContractSpecification: 1.0.0
+info:
+ title: Data Contract
+ version: 1.0.0
+`
+ );
+
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{ name: string; type: string }>;
+ };
+ expect(config.contracts[0].type).toBe('odcs');
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/13-openapi-params-and-metadata.test.ts b/tests/e2e/13-openapi-params-and-metadata.test.ts
new file mode 100644
index 0000000..b69e486
--- /dev/null
+++ b/tests/e2e/13-openapi-params-and-metadata.test.ts
@@ -0,0 +1,120 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+function setupPetstore31(dir: string) {
+ setupRepoWithConfig(dir, [
+ { name: 'petstore', type: 'openapi', path: 'specs/petstore.yaml' },
+ ]);
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+}
+
+describe('OpenAPI parameter classification', () => {
+ test('adding optional parameter is non-breaking', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-nonbreaking-optional-param.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('adding required parameter is breaking', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-breaking-required-param.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
+
+describe('OpenAPI metadata change detection', () => {
+ test('description/summary changes are detected as patch (not breaking)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-description-changed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ // Description changes should not be breaking
+ const result = run('breaking', dir);
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('description changes create a changeset', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-description-changed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('changeset', dir);
+ expect(result.exitCode).toBe(0);
+ // Should create a changeset (not "No changes detected")
+ expect(result.stdout).toMatch(/created changeset/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('description changes detected in diff command', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-description-changed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff', dir);
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/change|patch|description/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/14-openapi-message-formatting.test.ts b/tests/e2e/14-openapi-message-formatting.test.ts
new file mode 100644
index 0000000..41898e4
--- /dev/null
+++ b/tests/e2e/14-openapi-message-formatting.test.ts
@@ -0,0 +1,181 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+function setupPetstore31(dir: string) {
+ setupRepoWithConfig(dir, [
+ { name: 'petstore', type: 'openapi', path: 'specs/petstore.yaml' },
+ ]);
+ copyFixture(
+ 'openapi/petstore-31-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+}
+
+describe('OpenAPI change message formatting', () => {
+ test('path-added shows a readable message (not "Unknown change")', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'petstore', type: 'openapi', path: 'specs/petstore.yaml' },
+ ]);
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ copyFixture(
+ 'openapi/petstore-nonbreaking-endpoint-added.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ const changes = parsed.contracts?.petstore?.changes ?? [];
+
+ // Find the path-added change
+ const pathAdded = changes.find((c: { category: string }) => c.category === 'path-added');
+ expect(pathAdded).toBeDefined();
+ expect(pathAdded.message).not.toMatch(/unknown change/i);
+ expect(pathAdded.message).toMatch(/new path added/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('path paths in messages are decoded from JSON Pointer', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'petstore', type: 'openapi', path: 'specs/petstore.yaml' },
+ ]);
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff --format json', dir, { expectFail: false });
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ const changes = parsed.contracts?.petstore?.changes ?? [];
+
+ // All messages should be decoded (no ~1 or ~0 escapes)
+ for (const change of changes) {
+ expect(change.message).not.toMatch(/~1/);
+ expect(change.message).not.toMatch(/~0/);
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('operation-added shows readable message', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-nonbreaking-optional-param.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ const changes = parsed.contracts?.petstore?.changes ?? [];
+
+ // parameter-added case
+ const paramAdded = changes.find(
+ (c: { category: string }) => c.category === 'parameter-added'
+ );
+ expect(paramAdded).toBeDefined();
+ expect(paramAdded.message).not.toMatch(/unknown change/i);
+ expect(paramAdded.message).toMatch(/optional parameter added/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('required parameter added shows specific message', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-breaking-required-param.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ const changes = parsed.contracts?.petstore?.changes ?? [];
+
+ const reqParam = changes.find(
+ (c: { category: string }) => c.category === 'parameter-required-added'
+ );
+ expect(reqParam).toBeDefined();
+ expect(reqParam.message).not.toMatch(/unknown change/i);
+ expect(reqParam.message).toMatch(/required parameter added/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('no "Unknown change" messages for any OpenAPI structural change', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupPetstore31(dir);
+ copyFixture(
+ 'openapi/petstore-31-description-changed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ const result = run('diff --format json', dir);
+ expect(result.exitCode).toBe(0);
+ const parsed = JSON.parse(result.stdout);
+ const changes = parsed.contracts?.petstore?.changes ?? [];
+
+ expect(changes.length).toBeGreaterThan(0);
+ for (const change of changes) {
+ expect(change.message).not.toMatch(/unknown change/i);
+ }
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/14-strands-conformance.test.ts b/tests/e2e/14-strands-conformance.test.ts
new file mode 100644
index 0000000..9da366a
--- /dev/null
+++ b/tests/e2e/14-strands-conformance.test.ts
@@ -0,0 +1,607 @@
+/**
+ * Strands API Conformance Tests
+ *
+ * Tests the compareSchemas function against expected Strands API behavior.
+ * Based on the Strands API at https://strands.octue.com/api/compare-schemas
+ */
+
+import { describe, test, expect } from 'vitest';
+import {
+ compareSchemas,
+ checkCompatibility,
+} from '../../packages/differs.json-schema/src/compare.js';
+import type {
+ CompareResult,
+ CompareOptions,
+ StrandsTrace,
+ StrandsCompatibility,
+ StrandsVersion,
+ SemanticVersion,
+ ResolvedSchema,
+} from '../../packages/differs.json-schema/src/types.js';
+
+describe('Strands API Conformance', () => {
+ describe('Basic comparison results', () => {
+ test('identical schemas return equal version', () => {
+ const schema: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ },
+ };
+
+ const result: CompareResult = compareSchemas(schema, schema);
+ expect(result.version).toBe('equal');
+ expect(result.traces).toHaveLength(0);
+ });
+
+ test('no changes returns equal with currentVersion', () => {
+ const schema: ResolvedSchema = { type: 'string' };
+ const options: CompareOptions = { currentVersion: '1.0.0' };
+ const result: CompareResult = compareSchemas(schema, schema, options);
+
+ expect(result.version).toBe('equal');
+ const expectedVersion: SemanticVersion = {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ version: '1.0.0',
+ };
+ expect(result.newVersion).toEqual(expectedVersion);
+ });
+ });
+
+ describe('Format changes are patch (not breaking)', () => {
+ test('format-added is patch', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'string', format: 'email' };
+
+ const result: CompareResult = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ expect(result.version).toBe('patch');
+ expect(result.newVersion?.version).toBe('1.0.1');
+ });
+
+ test('format-removed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', format: 'email' };
+ const target: ResolvedSchema = { type: 'string' };
+
+ const result: CompareResult = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ expect(result.version).toBe('patch');
+ });
+
+ test('format-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', format: 'email' };
+ const target: ResolvedSchema = { type: 'string', format: 'uri' };
+
+ const result: CompareResult = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ expect(result.version).toBe('patch');
+ });
+ });
+
+ describe('Type changes classification', () => {
+ test('type change is breaking (major)', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+
+ const result: CompareResult = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ expect(result.version).toBe('major');
+ expect(result.newVersion?.version).toBe('2.0.0');
+ });
+
+ test('type narrowed is breaking', () => {
+ const source: ResolvedSchema = { type: ['string', 'number'] };
+ const target: ResolvedSchema = { type: 'string' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('type widened is non-breaking (minor)', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: ['string', 'number'] };
+
+ const result: CompareResult = compareSchemas(source, target, { currentVersion: '1.0.0' });
+ expect(result.version).toBe('minor');
+ expect(result.newVersion?.version).toBe('1.1.0');
+ });
+ });
+
+ describe('Property changes classification', () => {
+ test('property-added is non-breaking (minor)', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ email: { type: 'string' },
+ },
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('property-removed is breaking (major)', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ email: { type: 'string' },
+ },
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('required-added is breaking', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ required: ['name'],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('required-removed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ required: ['name'],
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+ });
+
+ describe('Enum changes classification', () => {
+ test('enum-value-added is non-breaking', () => {
+ const source: ResolvedSchema = { type: 'string', enum: ['a', 'b'] };
+ const target: ResolvedSchema = { type: 'string', enum: ['a', 'b', 'c'] };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('enum-value-removed is breaking', () => {
+ const source: ResolvedSchema = { type: 'string', enum: ['a', 'b', 'c'] };
+ const target: ResolvedSchema = { type: 'string', enum: ['a', 'b'] };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('enum-added is breaking', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'string', enum: ['a', 'b'] };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('enum-removed is non-breaking', () => {
+ const source: ResolvedSchema = { type: 'string', enum: ['a', 'b'] };
+ const target: ResolvedSchema = { type: 'string' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+ });
+
+ describe('Constraint changes classification', () => {
+ test('constraint-tightened is breaking', () => {
+ const source: ResolvedSchema = { type: 'number', minimum: 0 };
+ const target: ResolvedSchema = { type: 'number', minimum: 10 };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('constraint-loosened is non-breaking', () => {
+ const source: ResolvedSchema = { type: 'number', minimum: 10 };
+ const target: ResolvedSchema = { type: 'number', minimum: 0 };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('minItems-increased is breaking', () => {
+ const source: ResolvedSchema = { type: 'array', items: { type: 'string' }, minItems: 1 };
+ const target: ResolvedSchema = { type: 'array', items: { type: 'string' }, minItems: 5 };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('maxItems-decreased is breaking', () => {
+ const source: ResolvedSchema = { type: 'array', items: { type: 'string' }, maxItems: 10 };
+ const target: ResolvedSchema = { type: 'array', items: { type: 'string' }, maxItems: 5 };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+ });
+
+ describe('additionalProperties changes', () => {
+ test('additionalProperties denied is breaking', () => {
+ const source: ResolvedSchema = { type: 'object', properties: { name: { type: 'string' } } };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ additionalProperties: false,
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('additionalProperties allowed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ additionalProperties: false,
+ };
+ const target: ResolvedSchema = { type: 'object', properties: { name: { type: 'string' } } };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+ });
+
+ describe('Metadata changes are patch', () => {
+ test('description-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', description: 'Old description' };
+ const target: ResolvedSchema = { type: 'string', description: 'New description' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+
+ test('title-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', title: 'Old title' };
+ const target: ResolvedSchema = { type: 'string', title: 'New title' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+
+ test('default-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', default: 'old' };
+ const target: ResolvedSchema = { type: 'string', default: 'new' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+
+ test('examples-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string', examples: ['old'] };
+ const target: ResolvedSchema = { type: 'string', examples: ['new'] };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+ });
+
+ describe('Annotation changes are patch (Draft 2019-09+)', () => {
+ test('deprecated-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'string', deprecated: true };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+
+ test('readOnly-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'string', readOnly: true };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+
+ test('writeOnly-changed is patch', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'string', writeOnly: true };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('patch');
+ });
+ });
+
+ describe('Composition changes (anyOf/oneOf/allOf)', () => {
+ test('anyOf option added is breaking', () => {
+ const source: ResolvedSchema = {
+ anyOf: [{ type: 'string' }, { type: 'number' }],
+ };
+ const target: ResolvedSchema = {
+ anyOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('anyOf option removed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ anyOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
+ };
+ const target: ResolvedSchema = {
+ anyOf: [{ type: 'string' }, { type: 'number' }],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('oneOf option added is breaking', () => {
+ const source: ResolvedSchema = {
+ oneOf: [{ type: 'string' }, { type: 'number' }],
+ };
+ const target: ResolvedSchema = {
+ oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('oneOf option removed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }],
+ };
+ const target: ResolvedSchema = {
+ oneOf: [{ type: 'string' }, { type: 'number' }],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('allOf member added is breaking', () => {
+ const source: ResolvedSchema = {
+ allOf: [{ type: 'object', properties: { a: { type: 'string' } } }],
+ };
+ const target: ResolvedSchema = {
+ allOf: [
+ { type: 'object', properties: { a: { type: 'string' } } },
+ { type: 'object', properties: { b: { type: 'number' } } },
+ ],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('allOf member removed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ allOf: [
+ { type: 'object', properties: { a: { type: 'string' } } },
+ { type: 'object', properties: { b: { type: 'number' } } },
+ ],
+ };
+ const target: ResolvedSchema = {
+ allOf: [{ type: 'object', properties: { a: { type: 'string' } } }],
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+
+ test('not schema changed is breaking', () => {
+ const source: ResolvedSchema = { not: { type: 'string' } };
+ const target: ResolvedSchema = { not: { type: 'number' } };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+ });
+
+ describe('Draft 2020-12 keywords', () => {
+ test('dependentRequired-added is breaking', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ creditCard: { type: 'string' },
+ billingAddress: { type: 'string' },
+ },
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ creditCard: { type: 'string' },
+ billingAddress: { type: 'string' },
+ },
+ dependentRequired: {
+ creditCard: ['billingAddress'],
+ },
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('major');
+ });
+
+ test('dependentRequired-removed is non-breaking', () => {
+ const source: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ creditCard: { type: 'string' },
+ billingAddress: { type: 'string' },
+ },
+ dependentRequired: {
+ creditCard: ['billingAddress'],
+ },
+ };
+ const target: ResolvedSchema = {
+ type: 'object',
+ properties: {
+ creditCard: { type: 'string' },
+ billingAddress: { type: 'string' },
+ },
+ };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.version).toBe('minor');
+ });
+ });
+
+ describe('Strands trace format', () => {
+ test('traces have correct format', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.traces.length).toBeGreaterThan(0);
+
+ const validCompatibilities: StrandsCompatibility[] = [
+ 'incompatible',
+ 'compatible',
+ 'unknown',
+ ];
+ for (const trace of result.traces) {
+ // Verify trace conforms to StrandsTrace interface
+ const typedTrace: StrandsTrace = trace;
+ expect(typedTrace).toHaveProperty('compatibility');
+ expect(typedTrace).toHaveProperty('left');
+ expect(typedTrace).toHaveProperty('right');
+ expect(validCompatibilities).toContain(typedTrace.compatibility);
+ }
+ });
+
+ test('breaking changes have incompatible traces', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ const hasIncompatible = result.traces.some(
+ (t: StrandsTrace) => t.compatibility === 'incompatible'
+ );
+ expect(hasIncompatible).toBe(true);
+ });
+
+ test('non-breaking changes have compatible traces', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: ['string', 'number'] };
+
+ const result: CompareResult = compareSchemas(source, target);
+ const hasCompatible = result.traces.some(
+ (t: StrandsTrace) => t.compatibility === 'compatible'
+ );
+ expect(hasCompatible).toBe(true);
+ });
+ });
+
+ describe('newVersion computation', () => {
+ test('computes newVersion correctly for major bump', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+ const options: CompareOptions = { currentVersion: '1.2.3' };
+
+ const result: CompareResult = compareSchemas(source, target, options);
+ const expectedVersion: SemanticVersion = {
+ major: 2,
+ minor: 0,
+ patch: 0,
+ version: '2.0.0',
+ };
+ expect(result.newVersion).toEqual(expectedVersion);
+ });
+
+ test('computes newVersion correctly for minor bump', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: ['string', 'number'] };
+ const options: CompareOptions = { currentVersion: '1.2.3' };
+
+ const result: CompareResult = compareSchemas(source, target, options);
+ const expectedVersion: SemanticVersion = {
+ major: 1,
+ minor: 3,
+ patch: 0,
+ version: '1.3.0',
+ };
+ expect(result.newVersion).toEqual(expectedVersion);
+ });
+
+ test('computes newVersion correctly for patch bump', () => {
+ const source: ResolvedSchema = { type: 'string', description: 'old' };
+ const target: ResolvedSchema = { type: 'string', description: 'new' };
+ const options: CompareOptions = { currentVersion: '1.2.3' };
+
+ const result: CompareResult = compareSchemas(source, target, options);
+ const expectedVersion: SemanticVersion = {
+ major: 1,
+ minor: 2,
+ patch: 4,
+ version: '1.2.4',
+ };
+ expect(result.newVersion).toEqual(expectedVersion);
+ });
+
+ test('handles v-prefix in currentVersion', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+ const options: CompareOptions = { currentVersion: 'v1.2.3' };
+
+ const result: CompareResult = compareSchemas(source, target, options);
+ expect(result.newVersion?.version).toBe('2.0.0');
+ });
+
+ test('newVersion is null when currentVersion not provided', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+
+ const result: CompareResult = compareSchemas(source, target);
+ expect(result.newVersion).toBeNull();
+ });
+ });
+
+ describe('checkCompatibility helper', () => {
+ test('returns incompatible for breaking changes', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: 'number' };
+
+ const compatibility: StrandsCompatibility = checkCompatibility(source, target);
+ expect(compatibility).toBe('incompatible');
+ });
+
+ test('returns compatible for non-breaking changes', () => {
+ const source: ResolvedSchema = { type: 'string' };
+ const target: ResolvedSchema = { type: ['string', 'number'] };
+
+ const compatibility: StrandsCompatibility = checkCompatibility(source, target);
+ expect(compatibility).toBe('compatible');
+ });
+
+ test('returns compatible for patch changes', () => {
+ const source: ResolvedSchema = { type: 'string', description: 'old' };
+ const target: ResolvedSchema = { type: 'string', description: 'new' };
+
+ const compatibility: StrandsCompatibility = checkCompatibility(source, target);
+ expect(compatibility).toBe('compatible');
+ });
+
+ test('returns compatible for identical schemas', () => {
+ const schema: ResolvedSchema = { type: 'string' };
+
+ const compatibility: StrandsCompatibility = checkCompatibility(schema, schema);
+ expect(compatibility).toBe('compatible');
+ });
+ });
+});
diff --git a/tests/e2e/15-json-schema-lint-rules.test.ts b/tests/e2e/15-json-schema-lint-rules.test.ts
new file mode 100644
index 0000000..a9165d6
--- /dev/null
+++ b/tests/e2e/15-json-schema-lint-rules.test.ts
@@ -0,0 +1,838 @@
+/**
+ * JSON Schema Lint Rules Tests
+ *
+ * Tests the linting rules for JSON Schema quality and best practices.
+ * Based on Sourcemeta and JSON Schema community guidelines.
+ *
+ * @see https://github.com/sourcemeta/jsonschema
+ * @see https://github.com/orgs/json-schema-org/discussions/323
+ */
+
+import { describe, test, expect } from 'vitest';
+import {
+ runLintRules,
+ getAvailableRules,
+ getRuleDescription,
+ LINT_RULES,
+} from '../../packages/governance/linters/json-schema-rules.js';
+import { lintJsonSchemaObject } from '../../packages/governance/linters/json-schema-ajv.js';
+import type { SchemaNode } from '../../packages/governance/linters/json-schema-rules.js';
+import type { LintIssue } from '../../packages/types/governance.js';
+
+describe('JSON Schema Lint Rules', () => {
+ describe('Rule registry', () => {
+ test('all rules are registered', () => {
+ const ruleIds = getAvailableRules();
+ expect(ruleIds.length).toBeGreaterThan(15);
+ });
+
+ test('each rule has a description', () => {
+ for (const rule of LINT_RULES) {
+ expect(rule.description).toBeTruthy();
+ expect(getRuleDescription(rule.id)).toBe(rule.description);
+ }
+ });
+
+ test('each rule has a valid severity', () => {
+ for (const rule of LINT_RULES) {
+ expect(['error', 'warning']).toContain(rule.severity);
+ }
+ });
+ });
+
+ describe('Schema declaration rules', () => {
+ test('missing-schema: warns when $schema is missing at root', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-schema');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('warning');
+ expect(issue?.path).toBe('/');
+ });
+
+ test('missing-schema: no warning when $schema is present', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'string',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-schema');
+ expect(issue).toBeUndefined();
+ });
+
+ test('schema-not-at-root: warns when $schema appears in subschema without $id', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'object',
+ properties: {
+ nested: {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'string',
+ },
+ },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'schema-not-at-root');
+ expect(issue).toBeDefined();
+ expect(issue?.path).toContain('nested');
+ });
+
+ test('schema-not-at-root: no warning when subschema has $id', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'object',
+ properties: {
+ nested: {
+ $id: 'https://example.com/nested',
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'string',
+ },
+ },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'schema-not-at-root');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Metadata rules', () => {
+ test('missing-title: warns when root schema has no title', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'string',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-title');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('warning');
+ });
+
+ test('missing-title: no warning when title is present', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ title: 'My Schema',
+ type: 'string',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-title');
+ expect(issue).toBeUndefined();
+ });
+
+ test('missing-description: warns when root schema has no description', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ type: 'string',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-description');
+ expect(issue).toBeDefined();
+ });
+
+ test('missing-description: no warning when description is present', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ description: 'A string value',
+ type: 'string',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'missing-description');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Enum/Const rules', () => {
+ test('enum-to-const: warns when enum has single value', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['only-value'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'enum-to-const');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('const');
+ });
+
+ test('enum-to-const: no warning when enum has multiple values', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['a', 'b', 'c'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'enum-to-const');
+ expect(issue).toBeUndefined();
+ });
+
+ test('enum-with-type: warns when type is redundant with enum', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['a', 'b', 'c'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'enum-with-type');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('redundant');
+ });
+
+ test('enum-with-type: no warning when enum has mixed types', () => {
+ const schema: SchemaNode = {
+ type: ['string', 'number'],
+ enum: ['a', 1, 'b', 2],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'enum-with-type');
+ // Should still warn because enum constrains to the same types
+ expect(issue).toBeDefined();
+ });
+
+ test('const-with-type: warns when type is redundant with const', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ const: 'fixed-value',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'const-with-type');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('redundant');
+ });
+
+ test('const-with-type: no warning when type differs from const', () => {
+ const schema: SchemaNode = {
+ type: ['string', 'null'],
+ const: 'fixed-value',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'const-with-type');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Conditional schema rules', () => {
+ test('if-without-then-else: warns when if has no then or else', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ if: { properties: { type: { const: 'a' } } },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'if-without-then-else');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('no effect');
+ });
+
+ test('if-without-then-else: no warning when if has then', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ if: { properties: { type: { const: 'a' } } },
+ then: { required: ['extra'] },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'if-without-then-else');
+ expect(issue).toBeUndefined();
+ });
+
+ test('if-without-then-else: no warning when if has else', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ if: { properties: { type: { const: 'a' } } },
+ else: { required: ['other'] },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'if-without-then-else');
+ expect(issue).toBeUndefined();
+ });
+
+ test('then-else-without-if: warns when then appears without if', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ then: { required: ['extra'] },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'then-else-without-if');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('then');
+ });
+
+ test('then-else-without-if: warns when else appears without if', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ else: { required: ['other'] },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'then-else-without-if');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('else');
+ });
+ });
+
+ describe('Array constraint rules', () => {
+ test('additional-items-redundant: warns when additionalItems with schema items', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ items: { type: 'string' },
+ additionalItems: { type: 'number' },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'additional-items-redundant');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('ignored');
+ });
+
+ test('additional-items-redundant: no warning when items is tuple', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ items: [{ type: 'string' }, { type: 'number' }],
+ additionalItems: { type: 'boolean' },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'additional-items-redundant');
+ expect(issue).toBeUndefined();
+ });
+
+ test('contains-required: warns when minContains without contains', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ minContains: 2,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'contains-required');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('minContains');
+ });
+
+ test('contains-required: warns when maxContains without contains', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ maxContains: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'contains-required');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('maxContains');
+ });
+
+ test('contains-required: no warning when contains is present', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ contains: { type: 'string' },
+ minContains: 2,
+ maxContains: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'contains-required');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Type compatibility rules', () => {
+ test('type-incompatible-keywords: warns when string keywords on number type', () => {
+ const schema: SchemaNode = {
+ type: 'number',
+ minLength: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'type-incompatible-keywords');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('minLength');
+ expect(issue?.message).toContain('string');
+ });
+
+ test('type-incompatible-keywords: warns when array keywords on object type', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ minItems: 1,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'type-incompatible-keywords');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('minItems');
+ expect(issue?.message).toContain('array');
+ });
+
+ test('type-incompatible-keywords: warns when numeric keywords on string type', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ minimum: 0,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'type-incompatible-keywords');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('minimum');
+ });
+
+ test('type-incompatible-keywords: no warning when keywords match type', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ minLength: 1,
+ maxLength: 100,
+ pattern: '^[a-z]+$',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'type-incompatible-keywords');
+ expect(issue).toBeUndefined();
+ });
+
+ test('type-incompatible-keywords: no check when type is array (multiple types)', () => {
+ const schema: SchemaNode = {
+ type: ['string', 'number'],
+ minLength: 1,
+ minimum: 0,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'type-incompatible-keywords');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Range validation rules', () => {
+ test('invalid-numeric-range: errors when maximum < minimum', () => {
+ const schema: SchemaNode = {
+ type: 'number',
+ minimum: 100,
+ maximum: 10,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-numeric-range');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ expect(issue?.message).toContain('maximum');
+ expect(issue?.message).toContain('minimum');
+ });
+
+ test('invalid-numeric-range: no error when maximum >= minimum', () => {
+ const schema: SchemaNode = {
+ type: 'number',
+ minimum: 0,
+ maximum: 100,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-numeric-range');
+ expect(issue).toBeUndefined();
+ });
+
+ test('invalid-numeric-range: errors when exclusiveMaximum <= exclusiveMinimum', () => {
+ const schema: SchemaNode = {
+ type: 'number',
+ exclusiveMinimum: 10,
+ exclusiveMaximum: 10,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-numeric-range');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('exclusiveMaximum');
+ });
+
+ test('invalid-length-range: errors when maxLength < minLength', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ minLength: 10,
+ maxLength: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-length-range');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ });
+
+ test('invalid-items-range: errors when maxItems < minItems', () => {
+ const schema: SchemaNode = {
+ type: 'array',
+ minItems: 10,
+ maxItems: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-items-range');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ });
+
+ test('invalid-properties-range: errors when maxProperties < minProperties', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ minProperties: 10,
+ maxProperties: 5,
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-properties-range');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ });
+ });
+
+ describe('Format rules', () => {
+ test('unknown-format: warns for unknown format values', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ format: 'custom-format',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'unknown-format');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('custom-format');
+ });
+
+ test('unknown-format: no warning for known formats', () => {
+ const knownFormats = [
+ 'date-time',
+ 'date',
+ 'time',
+ 'email',
+ 'uri',
+ 'uuid',
+ 'ipv4',
+ 'ipv6',
+ 'hostname',
+ 'regex',
+ ];
+
+ for (const format of knownFormats) {
+ const schema: SchemaNode = { type: 'string', format };
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'unknown-format');
+ expect(issue).toBeUndefined();
+ }
+ });
+ });
+
+ describe('Empty schema rules', () => {
+ test('empty-enum: errors when enum is empty array', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: [],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'empty-enum');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ expect(issue?.message).toContain('never validate');
+ });
+
+ test('empty-required: warns when required is empty array', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: { name: { type: 'string' } },
+ required: [],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'empty-required');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('warning');
+ });
+
+ test('empty-allof-anyof-oneof: errors when anyOf is empty', () => {
+ const schema: SchemaNode = {
+ anyOf: [],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'empty-allof-anyof-oneof');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ });
+
+ test('empty-allof-anyof-oneof: errors when oneOf is empty', () => {
+ const schema: SchemaNode = {
+ oneOf: [],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'empty-allof-anyof-oneof');
+ expect(issue).toBeDefined();
+ expect(issue?.severity).toBe('error');
+ });
+
+ test('empty-allof-anyof-oneof: warns when allOf is empty', () => {
+ const schema: SchemaNode = {
+ allOf: [],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'empty-allof-anyof-oneof');
+ expect(issue).toBeDefined();
+ // allOf empty is just redundant, not invalid
+ expect(issue?.severity).toBe('warning');
+ });
+ });
+
+ describe('Required properties rules', () => {
+ test('required-undefined-property: warns when required property not in properties', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ },
+ required: ['name', 'email'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'required-undefined-property');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('email');
+ });
+
+ test('required-undefined-property: no warning when all required are defined', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ email: { type: 'string' },
+ },
+ required: ['name', 'email'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'required-undefined-property');
+ expect(issue).toBeUndefined();
+ });
+
+ test('duplicate-required: warns when required has duplicates', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ },
+ required: ['name', 'name'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'duplicate-required');
+ expect(issue).toBeDefined();
+ expect(issue?.message).toContain('name');
+ });
+
+ test('duplicate-required: no warning when required has no duplicates', () => {
+ const schema: SchemaNode = {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ email: { type: 'string' },
+ },
+ required: ['name', 'email'],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'duplicate-required');
+ expect(issue).toBeUndefined();
+ });
+ });
+
+ describe('Nested schema linting', () => {
+ test('rules apply to nested properties', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ title: 'Root',
+ description: 'Root schema',
+ type: 'object',
+ properties: {
+ nested: {
+ type: 'object',
+ properties: {
+ value: {
+ type: 'number',
+ minimum: 100,
+ maximum: 10, // Invalid range
+ },
+ },
+ },
+ },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-numeric-range');
+ expect(issue).toBeDefined();
+ expect(issue?.path).toContain('nested');
+ expect(issue?.path).toContain('value');
+ });
+
+ test('rules apply to items schema', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ title: 'Root',
+ description: 'Root schema',
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: ['only'], // Should suggest const
+ },
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'enum-to-const');
+ expect(issue).toBeDefined();
+ expect(issue?.path).toContain('items');
+ });
+
+ test('rules apply to allOf/anyOf/oneOf schemas', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ title: 'Root',
+ description: 'Root schema',
+ anyOf: [
+ { type: 'string', minLength: 10, maxLength: 5 }, // Invalid range
+ { type: 'number' },
+ ],
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-length-range');
+ expect(issue).toBeDefined();
+ expect(issue?.path).toContain('anyOf');
+ });
+
+ test('rules apply to $defs schemas', () => {
+ const schema: SchemaNode = {
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
+ title: 'Root',
+ description: 'Root schema',
+ $defs: {
+ BadDef: {
+ type: 'array',
+ minItems: 10,
+ maxItems: 5, // Invalid range
+ },
+ },
+ $ref: '#/$defs/BadDef',
+ };
+
+ const issues = runLintRules(schema);
+ const issue = issues.find((i) => i.rule === 'invalid-items-range');
+ expect(issue).toBeDefined();
+ expect(issue?.path).toContain('$defs');
+ });
+ });
+
+ describe('Rule filtering', () => {
+ test('enabledRules filters to only specified rules', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['only'],
+ minLength: 10,
+ maxLength: 5,
+ };
+
+ const enabledRules = new Set(['enum-to-const']);
+ const issues = runLintRules(schema, enabledRules);
+
+ expect(issues.length).toBe(1);
+ expect(issues[0].rule).toBe('enum-to-const');
+ });
+
+ test('disabledRules excludes specified rules', () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['only'],
+ };
+
+ const disabledRules = new Set(['enum-to-const', 'enum-with-type']);
+ const issues = runLintRules(schema, undefined, disabledRules);
+
+ const enumIssues = issues.filter(
+ (i) => i.rule === 'enum-to-const' || i.rule === 'enum-with-type'
+ );
+ expect(enumIssues).toHaveLength(0);
+ });
+ });
+
+ describe('Full linter integration (lintJsonSchemaObject)', () => {
+ test('combines meta-validation and style rules', async () => {
+ const schema: SchemaNode = {
+ type: 'objekt', // Invalid type value (meta-validation error)
+ enum: ['only'], // Style warning
+ };
+
+ const result = await lintJsonSchemaObject(schema);
+
+ // Should have meta-validation error
+ expect(result.errors.length).toBeGreaterThan(0);
+
+ // Should have style warnings
+ expect(result.warnings.length).toBeGreaterThan(0);
+ });
+
+ test('skipMetaValidation option works', async () => {
+ const schema: SchemaNode = {
+ type: 'objekt', // Invalid but should be skipped
+ };
+
+ const result = await lintJsonSchemaObject(schema, { skipMetaValidation: true });
+
+ // Should not have meta-validation errors
+ const metaErrors = result.errors.filter((e) => e.rule?.startsWith('meta:'));
+ expect(metaErrors).toHaveLength(0);
+ });
+
+ test('skipStyleRules option works', async () => {
+ const schema: SchemaNode = {
+ type: 'string',
+ enum: ['only'], // Should be skipped
+ };
+
+ const result = await lintJsonSchemaObject(schema, { skipStyleRules: true });
+
+ // Should not have style rule warnings
+ const styleWarnings = result.warnings.filter((w) => w.rule === 'enum-to-const');
+ expect(styleWarnings).toHaveLength(0);
+ });
+
+ test('valid schema with best practices passes all checks', async () => {
+ const schema: SchemaNode = {
+ $schema: 'http://json-schema.org/draft-07/schema#',
+ title: 'User',
+ description: 'A user object',
+ type: 'object',
+ properties: {
+ id: { type: 'string', format: 'uuid' },
+ name: { type: 'string', minLength: 1, maxLength: 100 },
+ email: { type: 'string', format: 'email' },
+ age: { type: 'integer', minimum: 0, maximum: 150 },
+ },
+ required: ['id', 'name', 'email'],
+ additionalProperties: false,
+ };
+
+ const result = await lintJsonSchemaObject(schema);
+
+ expect(result.errors).toHaveLength(0);
+ // May have some warnings (like missing-description on nested props)
+ });
+ });
+});
diff --git a/tests/e2e/16-diff-command.test.ts b/tests/e2e/16-diff-command.test.ts
new file mode 100644
index 0000000..3a217de
--- /dev/null
+++ b/tests/e2e/16-diff-command.test.ts
@@ -0,0 +1,633 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual diff', () => {
+ describe('basic functionality', () => {
+ test('shows "no changes" when specs match snapshots', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Create snapshot matching current spec
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no changes/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows classified changes when specs differ from snapshots', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Current spec has a field removed (breaking change)
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ // Snapshot is the base version
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order-schema/i);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('always exits 0 on success regardless of breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Breaking change: field removed
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff', dir);
+
+ // diff always exits 0 (unlike breaking which exits 1)
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('options', () => {
+ test('--contract filters to single contract', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-schema',
+ type: 'json-schema',
+ path: 'schemas/user.json',
+ },
+ ]);
+
+ // Both have changes
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/user.json')
+ );
+
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/user-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'user-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --contract order-schema', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order-schema/i);
+ expect(result.stdout).not.toMatch(/user-schema/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--format json outputs valid JSON', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --format json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(output).toHaveProperty('contracts');
+ expect(typeof output.contracts).toBe('object');
+
+ const contractNames = Object.keys(output.contracts);
+ if (contractNames.length > 0) {
+ const firstContract = output.contracts[contractNames[0]];
+ expect(firstContract).toHaveProperty('changes');
+ expect(firstContract).toHaveProperty('summary');
+ expect(firstContract).toHaveProperty('suggestedBump');
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--severity breaking filters to only breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Use a spec that has both breaking and non-breaking changes
+ // For this we need a spec with field removed (breaking) and description changed (patch)
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --severity breaking --format json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ // All changes in contracts should be breaking
+ for (const contractName in output.contracts) {
+ const contract = output.contracts[contractName];
+ for (const change of contract.changes) {
+ expect(change.severity).toBe('breaking');
+ }
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--severity non-breaking filters to only non-breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Non-breaking: optional field added
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --severity non-breaking --format json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ // All changes should be non-breaking
+ for (const contractName in output.contracts) {
+ const contract = output.contracts[contractName];
+ for (const change of contract.changes) {
+ expect(change.severity).toBe('non-breaking');
+ }
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--verbose shows JSON Pointer paths', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff --verbose', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Verbose output should include "path:" lines
+ expect(result.stdout).toMatch(/path:/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('edge cases', () => {
+ test('shows "no changes" for first version (no snapshot)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // No snapshot exists - first version
+
+ const result = run('diff', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should indicate first version or no changes
+ expect(result.stdout).toMatch(/no changes|first version|no snapshot/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('exits with error on configuration error', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // No contractual.yaml - should fail
+
+ const result = run('diff', dir, { expectFail: true });
+
+ expect(result.exitCode).toBeGreaterThan(0);
+ expect(result.stdout + result.stderr).toMatch(/init|config|not found/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('handles contract with breaking detection disabled', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ breaking: false, // Disabled
+ },
+ ]);
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should indicate skipped or disabled
+ expect(result.stdout).toMatch(/disabled|skipped|no changes/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('reports error for non-existent contract name', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('diff --contract nonexistent', dir, { expectFail: true });
+
+ expect(result.exitCode).toBeGreaterThan(0);
+ expect(result.stdout + result.stderr).toMatch(/not found|nonexistent/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('OpenAPI contracts', () => {
+ test('shows changes for OpenAPI specs', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore-api',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ lint: false, // Disable linting for petstore fixture
+ },
+ ]);
+
+ // Current spec has endpoint removed (breaking)
+ copyFixture(
+ 'openapi/petstore-breaking-endpoint-removed.yaml',
+ path.join(dir, 'specs/petstore.yaml')
+ );
+
+ // Snapshot is base version
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore-api.yaml')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'petstore-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('diff', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/petstore-api/i);
+ expect(result.stdout).toMatch(/breaking/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
+
+describe('breaking command after refactor', () => {
+ test('still exits 1 on breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('still exits 0 when no breaking changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Non-breaking change only
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('breaking', dir);
+
+ expect(result.exitCode).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+});
+
+describe('changeset command after refactor', () => {
+ test('still generates changeset from detected changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('changeset', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/created changeset/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('still shows "no changes" when specs match', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('changeset', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/no change/i);
+ } finally {
+ cleanup();
+ }
+ });
+});
diff --git a/tests/e2e/17-pre-release.test.ts b/tests/e2e/17-pre-release.test.ts
new file mode 100644
index 0000000..76069b2
--- /dev/null
+++ b/tests/e2e/17-pre-release.test.ts
@@ -0,0 +1,403 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ fileExists,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual pre', () => {
+ describe('pre enter', () => {
+ test('enters pre-release mode with tag', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const result = run('pre enter beta', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/entered pre-release mode/i);
+ expect(result.stdout).toMatch(/beta/i);
+ expect(fileExists(dir, '.contractual/pre.json')).toBe(true);
+
+ const preState = readJSON(dir, '.contractual/pre.json') as {
+ tag: string;
+ enteredAt: string;
+ initialVersions: Record;
+ };
+ expect(preState.tag).toBe('beta');
+ expect(preState.initialVersions['order-schema']).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('creates pre.json with correct structure', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api',
+ type: 'json-schema',
+ path: 'schemas/api.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/api.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '2.5.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ run('pre enter alpha', dir);
+
+ const preState = readJSON(dir, '.contractual/pre.json') as {
+ tag: string;
+ enteredAt: string;
+ initialVersions: Record;
+ };
+
+ expect(preState.tag).toBe('alpha');
+ expect(preState.enteredAt).toBeDefined();
+ expect(new Date(preState.enteredAt).getTime()).not.toBeNaN();
+ expect(preState.initialVersions).toEqual({ api: '2.5.0' });
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if already in pre-release mode', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Enter pre-release mode first
+ run('pre enter beta', dir);
+
+ // Try to enter again
+ const result = run('pre enter alpha', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/already in pre-release mode/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if not initialized', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // No contractual.yaml or .contractual directory
+
+ const result = run('pre enter beta', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/no .contractual directory|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('pre exit', () => {
+ test('exits pre-release mode', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Enter and then exit
+ run('pre enter beta', dir);
+ expect(fileExists(dir, '.contractual/pre.json')).toBe(true);
+
+ const result = run('pre exit', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/exited pre-release mode/i);
+ expect(fileExists(dir, '.contractual/pre.json')).toBe(false);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows message if not in pre-release mode', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('pre exit', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/not in pre-release mode/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if not initialized', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ const result = run('pre exit', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/no .contractual directory|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('pre status', () => {
+ test('shows current pre-release tag and entry time', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ run('pre enter rc', dir);
+
+ const result = run('pre status', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/rc/i);
+ expect(result.stdout).toMatch(/tag|pre-release/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows "not in pre-release mode" when inactive', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('pre status', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/not in pre-release mode/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if not initialized', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ const result = run('pre status', dir, { expectFail: true });
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/no .contractual directory|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('version with pre-release', () => {
+ test('bumps to pre-release version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Setup initial state
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture('json-schema/order-field-removed.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Enter pre-release mode
+ run('pre enter beta', dir);
+
+ // Create changeset
+ const changeset = `---
+"order-schema": major
+---
+
+Breaking change for beta testing
+`;
+ writeFile(dir, '.contractual/changesets/breaking.md', changeset);
+
+ // Run version
+ const result = run('version --yes', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Check version is pre-release format
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toMatch(/2\.0\.0-beta/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('increments pre-release number on subsequent versions', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+
+ // Start with a pre-release version already
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+ copyFixture(
+ 'json-schema/order-optional-field-added.json',
+ path.join(dir, 'schemas/order.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '2.0.0-beta.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create pre.json to simulate being in pre-release mode
+ writeFile(
+ dir,
+ '.contractual/pre.json',
+ JSON.stringify({
+ tag: 'beta',
+ enteredAt: '2026-01-01T00:00:00Z',
+ initialVersions: { 'order-schema': '1.0.0' },
+ })
+ );
+
+ // Create changeset
+ const changeset = `---
+"order-schema": minor
+---
+
+Another beta change
+`;
+ writeFile(dir, '.contractual/changesets/minor.md', changeset);
+
+ // Run version
+ const result = run('version --yes', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Check version incremented pre-release number
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ // Should be 2.1.0-beta.0 or 2.0.0-beta.1 depending on implementation
+ expect(versions['order-schema'].version).toMatch(/beta/);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/18-contract-management.test.ts b/tests/e2e/18-contract-management.test.ts
new file mode 100644
index 0000000..c7305a4
--- /dev/null
+++ b/tests/e2e/18-contract-management.test.ts
@@ -0,0 +1,312 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ readYAML,
+ fileExists,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual contract', () => {
+ describe('contract add', () => {
+ test('adds contract to existing config', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Initialize with one contract
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Add a new spec file
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Add contract using CLI
+ const result = run(
+ 'contract add --name user-schema --type json-schema --path schemas/user.json --initial-version 0.0.0 -y',
+ dir
+ );
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/added.*user-schema/i);
+
+ // Verify config was updated
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{ name: string; type: string; path: string }>;
+ };
+ expect(config.contracts).toHaveLength(2);
+ expect(config.contracts.find((c) => c.name === 'user-schema')).toBeDefined();
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('creates snapshot and updates versions.json', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Add new contract
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/new-api.json'));
+
+ const result = run(
+ 'contract add --name new-api --type json-schema --path schemas/new-api.json --initial-version 0.5.0 -y',
+ dir
+ );
+
+ expect(result.exitCode).toBe(0);
+
+ // Verify snapshot created
+ expect(fileExists(dir, '.contractual/snapshots/new-api.json')).toBe(true);
+
+ // Verify versions.json updated
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['new-api'].version).toBe('0.5.0');
+ expect(versions['order-schema'].version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('validates spec file type', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Create a non-matching spec file (JSON Schema file but claim it's OpenAPI)
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/fake-api.json'));
+
+ const result = run(
+ 'contract add --name fake-api --type openapi --path schemas/fake-api.json -y',
+ dir,
+ { expectFail: true }
+ );
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout).toMatch(/type mismatch|invalid|detected/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--skip-validation bypasses type check', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Create file
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/custom.json'));
+
+ const result = run(
+ 'contract add --name custom-api --type openapi --path schemas/custom.json --skip-validation -y',
+ dir
+ );
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/added.*custom-api/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if not initialized', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // No contractual.yaml
+
+ const result = run(
+ 'contract add --name test --type json-schema --path test.json -y',
+ dir,
+ { expectFail: true }
+ );
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/not initialized|init/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('fails if contract name already exists', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ // Try to add with same name
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/other.json'));
+
+ const result = run(
+ 'contract add --name order-schema --type json-schema --path schemas/other.json -y',
+ dir,
+ { expectFail: true }
+ );
+
+ expect(result.exitCode).toBe(1);
+ expect(result.stdout + result.stderr).toMatch(/contract exists|already defined|duplicate/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('contract list', () => {
+ test('lists all contracts', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-api',
+ type: 'openapi',
+ path: 'specs/user.yaml',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/user.yaml'));
+
+ const result = run('contract list', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).toMatch(/user-api/);
+ expect(result.stdout).toMatch(/json-schema/);
+ expect(result.stdout).toMatch(/openapi/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('filters by exact name', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ {
+ name: 'user-schema',
+ type: 'json-schema',
+ path: 'schemas/user.json',
+ },
+ {
+ name: 'product-api',
+ type: 'openapi',
+ path: 'specs/product.yaml',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/product.yaml'));
+
+ const result = run('contract list order-schema', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).not.toMatch(/user-schema/);
+ expect(result.stdout).not.toMatch(/product-api/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--json outputs structured JSON', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ const result = run('contract list --json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(Array.isArray(output)).toBe(true);
+ expect(output[0].name).toBe('order-schema');
+ expect(output[0].type).toBe('json-schema');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('shows message when no contracts (schema requires at least one)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Schema validation requires at least one contract, so empty array fails
+ writeFile(dir, 'contractual.yaml', 'contracts: []\n');
+
+ const result = run('contract list', dir, { expectFail: true });
+
+ // Schema validation fails on empty contracts array
+ expect(result.exitCode).toBeGreaterThan(0);
+ expect(result.stdout + result.stderr).toMatch(/must NOT have fewer than 1 items|invalid|contracts/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/19-init-enhanced.test.ts b/tests/e2e/19-init-enhanced.test.ts
new file mode 100644
index 0000000..074ebc4
--- /dev/null
+++ b/tests/e2e/19-init-enhanced.test.ts
@@ -0,0 +1,240 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ writeFile,
+ readJSON,
+ readYAML,
+ fileExists,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual init (enhanced)', () => {
+ describe('version options', () => {
+ test('--initial-version sets starting version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create a spec file
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ const result = run('init --initial-version 1.5.0 -y', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/v1\.5\.0/);
+
+ // Verify versions.json
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ const contractName = Object.keys(versions)[0];
+ expect(versions[contractName].version).toBe('1.5.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('-y uses default version (0.0.0)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ const result = run('init -y', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/v0\.0\.0/);
+
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ const contractName = Object.keys(versions)[0];
+ expect(versions[contractName].version).toBe('0.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('creates snapshots at initial version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ run('init --initial-version 2.0.0 -y', dir);
+
+ // Verify snapshot was created
+ expect(fileExists(dir, '.contractual/snapshots')).toBe(true);
+
+ // Find snapshot file
+ const config = readYAML(dir, 'contractual.yaml') as {
+ contracts: Array<{ name: string }>;
+ };
+ const contractName = config.contracts[0].name;
+
+ // Snapshot should exist (extension may vary)
+ const snapshotExists =
+ fileExists(dir, `.contractual/snapshots/${contractName}.json`) ||
+ fileExists(dir, `.contractual/snapshots/${contractName}.yaml`);
+ expect(snapshotExists).toBe(true);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('versioning modes', () => {
+ test('--versioning independent (default)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ const result = run('init --versioning independent -y', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Independent mode should not add versioning section (it's the default)
+ const config = readYAML(dir, 'contractual.yaml') as {
+ versioning?: { mode: string };
+ };
+ // Default mode doesn't need explicit config
+ expect(config.versioning?.mode).toBeUndefined();
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--versioning fixed', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ const result = run('init --versioning fixed -y', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const config = readYAML(dir, 'contractual.yaml') as {
+ versioning?: { mode: string };
+ };
+ expect(config.versioning?.mode).toBe('fixed');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('--force flag', () => {
+ test('reinitializes existing project', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ copyFixture('json-schema/order-base.json', path.join(dir, 'order.schema.json'));
+
+ // First init
+ run('init --initial-version 1.0.0 -y', dir);
+
+ // Verify first init
+ let versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ const contractName = Object.keys(versions)[0];
+ expect(versions[contractName].version).toBe('1.0.0');
+
+ // Force reinit with different version
+ const result = run('init --initial-version 2.0.0 --force -y', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Verify reinit
+ versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions[contractName].version).toBe('2.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('existing project handling', () => {
+ test('initializes unversioned contracts in existing project', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create config manually with two contracts
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: order-schema
+ type: json-schema
+ path: schemas/order.json
+ - name: user-schema
+ type: json-schema
+ path: schemas/user.json
+`
+ );
+
+ // Create spec files
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/user.json'));
+
+ // Create .contractual dir with only one contract versioned
+ writeFile(dir, '.contractual/versions.json', '{}');
+
+ // Run init - should detect unversioned contracts
+ const result = run('init -y', dir);
+
+ expect(result.exitCode).toBe(0);
+ // Should mention finding unversioned contracts
+ expect(result.stdout).toMatch(/without version|uninitialized|initialized/i);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('skips already versioned contracts', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create config
+ writeFile(
+ dir,
+ 'contractual.yaml',
+ `contracts:
+ - name: order-schema
+ type: json-schema
+ path: schemas/order.json
+`
+ );
+
+ // Create spec and snapshot
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Run init - should recognize all contracts have snapshots
+ const result = run('init -y', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/already initialized|all contracts have snapshots/i);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/20-version-enhanced.test.ts b/tests/e2e/20-version-enhanced.test.ts
new file mode 100644
index 0000000..7cd984b
--- /dev/null
+++ b/tests/e2e/20-version-enhanced.test.ts
@@ -0,0 +1,453 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readJSON,
+ fileExists,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('contractual version (enhanced)', () => {
+ describe('--dry-run', () => {
+ test('shows preview without applying changes', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // Create changeset
+ const changeset = `---
+"order-schema": minor
+---
+
+Added new feature
+`;
+ writeFile(dir, '.contractual/changesets/feature.md', changeset);
+
+ const result = run('version --dry-run', dir);
+
+ expect(result.exitCode).toBe(0);
+ expect(result.stdout).toMatch(/dry run|preview/i);
+ expect(result.stdout).toMatch(/order-schema/);
+ expect(result.stdout).toMatch(/1\.0\.0/);
+ expect(result.stdout).toMatch(/1\.1\.0|minor/);
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('does not modify versions.json', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": major
+---
+
+Breaking change
+`;
+ writeFile(dir, '.contractual/changesets/breaking.md', changeset);
+
+ run('version --dry-run', dir);
+
+ // Verify version unchanged
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('does not delete changesets', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": patch
+---
+
+Bug fix
+`;
+ writeFile(dir, '.contractual/changesets/fix.md', changeset);
+
+ run('version --dry-run', dir);
+
+ // Verify changeset still exists
+ const changesets = listFiles(dir, '.contractual/changesets');
+ expect(changesets).toContain('fix.md');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('--json', () => {
+ test('outputs structured JSON', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": minor
+---
+
+New feature
+`;
+ writeFile(dir, '.contractual/changesets/feature.md', changeset);
+
+ const result = run('version --json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(output.bumps).toBeDefined();
+ expect(Array.isArray(output.bumps)).toBe(true);
+
+ if (output.bumps.length > 0) {
+ expect(output.bumps[0].contract).toBe('order-schema');
+ expect(output.bumps[0].old).toBe('1.0.0');
+ expect(output.bumps[0].new).toBe('1.1.0');
+ expect(output.bumps[0].type).toBe('minor');
+ }
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('implies --yes (no prompts)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": minor
+---
+
+Feature
+`;
+ writeFile(dir, '.contractual/changesets/feat.md', changeset);
+
+ // --json should apply without prompting (implies --yes)
+ const result = run('version --json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Verify version was bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('works with --dry-run', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": major
+---
+
+Breaking
+`;
+ writeFile(dir, '.contractual/changesets/breaking.md', changeset);
+
+ const result = run('version --json --dry-run', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(output.dryRun).toBe(true);
+ expect(output.bumps).toBeDefined();
+
+ // Verify version NOT changed
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('-y/--yes', () => {
+ test('skips confirmation prompt', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order-schema.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"order-schema": patch
+---
+
+Fix
+`;
+ writeFile(dir, '.contractual/changesets/fix.md', changeset);
+
+ const result = run('version --yes', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ // Verify version was bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order-schema'].version).toBe('1.0.1');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('applies changes immediately', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'api-1',
+ type: 'json-schema',
+ path: 'schemas/api1.json',
+ },
+ {
+ name: 'api-2',
+ type: 'json-schema',
+ path: 'schemas/api2.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/api1.json'));
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/api2.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/api-1.json')
+ );
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/api-2.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'api-1': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'api-2': { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const changeset = `---
+"api-1": minor
+"api-2": major
+---
+
+Multiple changes
+`;
+ writeFile(dir, '.contractual/changesets/multi.md', changeset);
+
+ const result = run('version -y', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api-1'].version).toBe('1.1.0');
+ expect(versions['api-2'].version).toBe('3.0.0');
+
+ // Verify changeset was consumed
+ const changesets = listFiles(dir, '.contractual/changesets');
+ expect(changesets.filter((f) => f.endsWith('.md'))).toHaveLength(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('no changesets', () => {
+ test('shows message when no changesets with --json', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'order-schema',
+ type: 'json-schema',
+ path: 'schemas/order.json',
+ },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'order-schema': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ // No changesets
+
+ const result = run('version --json', dir);
+
+ expect(result.exitCode).toBe(0);
+
+ const output = JSON.parse(result.stdout);
+ expect(output.bumps).toHaveLength(0);
+ expect(output.changesets).toBe(0);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/21-spec-version-sync.test.ts b/tests/e2e/21-spec-version-sync.test.ts
new file mode 100644
index 0000000..cada4b9
--- /dev/null
+++ b/tests/e2e/21-spec-version-sync.test.ts
@@ -0,0 +1,992 @@
+import { describe, test, expect, beforeAll } from 'vitest';
+import path from 'node:path';
+import {
+ createTempRepo,
+ copyFixture,
+ run,
+ setupRepoWithConfig,
+ writeFile,
+ readFile,
+ readJSON,
+ readYAML,
+ fileExists,
+ listFiles,
+ ensureCliBuilt,
+} from './helpers.js';
+
+beforeAll(() => {
+ ensureCliBuilt();
+});
+
+describe('spec version sync', () => {
+ describe('OpenAPI (YAML)', () => {
+ test('updates info.version in spec on version bump', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'petstore', type: 'openapi', path: 'specs/petstore.yaml' },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+
+ // Copy to snapshot (simulating init)
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump-petstore.md',
+ `---\n"petstore": minor\n---\n\n## petstore\n- Added new endpoint\n`
+ );
+
+ const result = run('version', dir);
+ expect(result.exitCode).toBe(0);
+
+ // Spec file should have updated version
+ const spec = readYAML(dir, 'specs/petstore.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.1.0');
+
+ // Snapshot should also have updated version
+ const snapshot = readYAML(dir, '.contractual/snapshots/petstore.yaml') as {
+ info: { version: string };
+ };
+ expect(snapshot.info.version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('preserves YAML comments and formatting when updating version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ // Write a spec with comments
+ writeFile(
+ dir,
+ 'specs/api.yaml',
+ `# My API spec
+openapi: 3.0.3
+info:
+ title: My API
+ # Current version
+ version: 1.0.0
+paths: {}
+`
+ );
+
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/api.yaml')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": patch\n---\n\n## api\n- Fixed bug\n`
+ );
+
+ run('version', dir);
+
+ const content = readFile(dir, 'specs/api.yaml');
+ // Version updated
+ expect(content).toContain('version: 1.0.1');
+ // Comments preserved
+ expect(content).toContain('# My API spec');
+ expect(content).toContain('# Current version');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('OpenAPI (JSON)', () => {
+ test('updates info.version in JSON spec on version bump', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.json' },
+ ]);
+
+ writeFile(
+ dir,
+ 'specs/api.json',
+ JSON.stringify(
+ {
+ openapi: '3.0.3',
+ info: { title: 'My API', version: '2.0.0' },
+ paths: {},
+ },
+ null,
+ 2
+ ) + '\n'
+ );
+
+ // Snapshot
+ writeFile(
+ dir,
+ '.contractual/snapshots/api.json',
+ JSON.stringify(
+ {
+ openapi: '3.0.3',
+ info: { title: 'My API', version: '2.0.0' },
+ paths: {},
+ },
+ null,
+ 2
+ ) + '\n'
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": major\n---\n\n## api\n- Breaking change\n`
+ );
+
+ run('version', dir);
+
+ const spec = readJSON(dir, 'specs/api.json') as { info: { version: string } };
+ expect(spec.info.version).toBe('3.0.0');
+
+ // Snapshot too
+ const snapshot = readJSON(dir, '.contractual/snapshots/api.json') as {
+ info: { version: string };
+ };
+ expect(snapshot.info.version).toBe('3.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('JSON Schema (no version field)', () => {
+ test('does not modify json-schema spec (no standard version field)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'order', type: 'json-schema', path: 'schemas/order.json' },
+ ]);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const specBefore = readFile(dir, 'schemas/order.json');
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"order": minor\n---\n\n## order\n- Added field\n`
+ );
+
+ run('version', dir);
+
+ // Spec content should be unchanged (no version field to update)
+ const specAfter = readFile(dir, 'schemas/order.json');
+ expect(specAfter).toBe(specBefore);
+
+ // But versions.json should still be bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['order'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('syncVersion: false', () => {
+ test('does not update spec version when syncVersion is false', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ {
+ name: 'petstore',
+ type: 'openapi',
+ path: 'specs/petstore.yaml',
+ syncVersion: false,
+ },
+ ]);
+ copyFixture('openapi/petstore-base.yaml', path.join(dir, 'specs/petstore.yaml'));
+ copyFixture(
+ 'openapi/petstore-base.yaml',
+ path.join(dir, '.contractual/snapshots/petstore.yaml')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ petstore: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"petstore": minor\n---\n\n## petstore\n- Added endpoint\n`
+ );
+
+ run('version', dir);
+
+ // Spec should keep original version (1.0.27 from the fixture)
+ const spec = readYAML(dir, 'specs/petstore.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.27');
+
+ // But versions.json should still be bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['petstore'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('mixed: syncs one contract, skips another with syncVersion: false', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'synced-api', type: 'openapi', path: 'specs/synced.yaml' },
+ {
+ name: 'unsynced-api',
+ type: 'openapi',
+ path: 'specs/unsynced.yaml',
+ syncVersion: false,
+ },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: Test\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/synced.yaml', specContent);
+ writeFile(dir, 'specs/unsynced.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/synced-api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/unsynced-api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'synced-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'unsynced-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump-both.md',
+ `---\n"synced-api": minor\n"unsynced-api": minor\n---\n\n## synced-api\n- Change\n\n## unsynced-api\n- Change\n`
+ );
+
+ run('version', dir);
+
+ // Synced: spec version updated
+ const syncedSpec = readYAML(dir, 'specs/synced.yaml') as { info: { version: string } };
+ expect(syncedSpec.info.version).toBe('1.1.0');
+
+ // Unsynced: spec version unchanged
+ const unsyncedSpec = readYAML(dir, 'specs/unsynced.yaml') as {
+ info: { version: string };
+ };
+ expect(unsyncedSpec.info.version).toBe('1.0.0');
+
+ // Both bumped in versions.json
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['synced-api'].version).toBe('1.1.0');
+ expect(versions['unsynced-api'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('--no-sync-version CLI flag', () => {
+ test('skips spec version update when --no-sync-version is passed', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": minor\n---\n\n## api\n- Feature\n`
+ );
+
+ run('version --no-sync-version', dir);
+
+ // Spec should keep original version
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.0');
+
+ // But versions.json should still be bumped
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('--no-sync-version overrides syncVersion: true in config', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml', syncVersion: true },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": minor\n---\n\n## api\n- Feature\n`
+ );
+
+ run('version --no-sync-version', dir);
+
+ // CLI flag wins over config
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('missing version field in spec', () => {
+ test('creates info.version when missing from OpenAPI spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ // Write a spec WITHOUT info.version
+ writeFile(
+ dir,
+ 'specs/api.yaml',
+ `openapi: 3.0.3\ninfo:\n title: No Version API\npaths: {}\n`
+ );
+ writeFile(
+ dir,
+ '.contractual/snapshots/api.yaml',
+ `openapi: 3.0.3\ninfo:\n title: No Version API\npaths: {}\n`
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '0.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/initial.md',
+ `---\n"api": minor\n---\n\n## api\n- Initial feature\n`
+ );
+
+ run('version', dir);
+
+ // Version field should be created
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('0.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('creates info object and version when info is missing from OpenAPI spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ // Write a spec WITHOUT info at all
+ writeFile(dir, 'specs/api.yaml', `openapi: 3.0.3\npaths: {}\n`);
+ writeFile(dir, '.contractual/snapshots/api.yaml', `openapi: 3.0.3\npaths: {}\n`);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '0.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/initial.md',
+ `---\n"api": major\n---\n\n## api\n- Initial release\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info?: { version?: string } };
+ expect(spec.info).toBeDefined();
+ expect(spec.info!.version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('creates info.version in JSON spec when missing', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.json' },
+ ]);
+
+ const specNoVersion = { openapi: '3.0.3', info: { title: 'Test' }, paths: {} };
+ writeFile(dir, 'specs/api.json', JSON.stringify(specNoVersion, null, 2) + '\n');
+ writeFile(
+ dir,
+ '.contractual/snapshots/api.json',
+ JSON.stringify(specNoVersion, null, 2) + '\n'
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": patch\n---\n\n## api\n- Fix\n`
+ );
+
+ run('version', dir);
+
+ const spec = readJSON(dir, 'specs/api.json') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.1');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('all bump types', () => {
+ test('patch bump syncs spec version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.2.3\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.2.3', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/fix.md',
+ `---\n"api": patch\n---\n\n## api\n- Bug fix\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.2.4');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('minor bump syncs spec version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.2.3\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.2.3', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/feature.md',
+ `---\n"api": minor\n---\n\n## api\n- New feature\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.3.0');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('major bump syncs spec version', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 2.5.3\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '2.5.3', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/breaking.md',
+ `---\n"api": major\n---\n\n## api\n- Breaking change\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('3.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('first version (from 0.0.0)', () => {
+ test('syncs spec version on first bump from implicit 0.0.0', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ writeFile(
+ dir,
+ 'specs/api.yaml',
+ `openapi: 3.0.3\ninfo:\n title: New API\n version: 0.0.0\npaths: {}\n`
+ );
+ writeFile(
+ dir,
+ '.contractual/snapshots/api.yaml',
+ `openapi: 3.0.3\ninfo:\n title: New API\n version: 0.0.0\npaths: {}\n`
+ );
+
+ // No initial version in versions.json (first release)
+
+ writeFile(
+ dir,
+ '.contractual/changesets/initial.md',
+ `---\n"api": major\n---\n\n## api\n- Initial release\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.0');
+
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api'].version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('multiple changesets aggregation', () => {
+ test('spec gets the aggregated version (highest bump wins)', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ // Three changesets: patch, minor, major β major wins β 2.0.0
+ writeFile(
+ dir,
+ '.contractual/changesets/fix.md',
+ `---\n"api": patch\n---\n\n## api\n- Fix\n`
+ );
+ writeFile(
+ dir,
+ '.contractual/changesets/feature.md',
+ `---\n"api": minor\n---\n\n## api\n- Feature\n`
+ );
+ writeFile(
+ dir,
+ '.contractual/changesets/breaking.md',
+ `---\n"api": major\n---\n\n## api\n- Breaking\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('2.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('multi-contract', () => {
+ test('syncs version in multiple OpenAPI specs from one changeset', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'orders-api', type: 'openapi', path: 'specs/orders.yaml' },
+ { name: 'users-api', type: 'openapi', path: 'specs/users.yaml' },
+ ]);
+
+ const ordersSpec = `openapi: 3.0.3\ninfo:\n title: Orders\n version: 1.0.0\npaths: {}\n`;
+ const usersSpec = `openapi: 3.0.3\ninfo:\n title: Users\n version: 2.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/orders.yaml', ordersSpec);
+ writeFile(dir, 'specs/users.yaml', usersSpec);
+ writeFile(dir, '.contractual/snapshots/orders-api.yaml', ordersSpec);
+ writeFile(dir, '.contractual/snapshots/users-api.yaml', usersSpec);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'orders-api': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ 'users-api': { version: '2.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/update.md',
+ `---\n"orders-api": minor\n"users-api": patch\n---\n\n## orders-api\n- New endpoint\n\n## users-api\n- Fix typo\n`
+ );
+
+ run('version', dir);
+
+ const ordersResult = readYAML(dir, 'specs/orders.yaml') as { info: { version: string } };
+ expect(ordersResult.info.version).toBe('1.1.0');
+
+ const usersResult = readYAML(dir, 'specs/users.yaml') as { info: { version: string } };
+ expect(usersResult.info.version).toBe('2.0.1');
+
+ // Snapshots too
+ const ordersSnapshot = readYAML(dir, '.contractual/snapshots/orders-api.yaml') as {
+ info: { version: string };
+ };
+ expect(ordersSnapshot.info.version).toBe('1.1.0');
+
+ const usersSnapshot = readYAML(dir, '.contractual/snapshots/users-api.yaml') as {
+ info: { version: string };
+ };
+ expect(usersSnapshot.info.version).toBe('2.0.1');
+ } finally {
+ cleanup();
+ }
+ });
+
+ test('mixed types: syncs OpenAPI, skips JSON Schema', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ { name: 'order', type: 'json-schema', path: 'schemas/order.json' },
+ ]);
+
+ const apiSpec = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', apiSpec);
+ writeFile(dir, '.contractual/snapshots/api.yaml', apiSpec);
+ copyFixture('json-schema/order-base.json', path.join(dir, 'schemas/order.json'));
+ copyFixture(
+ 'json-schema/order-base.json',
+ path.join(dir, '.contractual/snapshots/order.json')
+ );
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ order: { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ const schemaBefore = readFile(dir, 'schemas/order.json');
+
+ writeFile(
+ dir,
+ '.contractual/changesets/bump.md',
+ `---\n"api": minor\n"order": minor\n---\n\n## api\n- Feature\n\n## order\n- Field added\n`
+ );
+
+ run('version', dir);
+
+ // OpenAPI spec updated
+ const apiResult = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(apiResult.info.version).toBe('1.1.0');
+
+ // JSON Schema unchanged
+ const schemaAfter = readFile(dir, 'schemas/order.json');
+ expect(schemaAfter).toBe(schemaBefore);
+
+ // Both bumped in versions.json
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api'].version).toBe('1.1.0');
+ expect(versions['order'].version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('pre-release version sync', () => {
+ test('syncs pre-release version into spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'api', type: 'openapi', path: 'specs/api.yaml' },
+ ]);
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 1.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+ writeFile(dir, '.contractual/snapshots/api.yaml', specContent);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ api: { version: '1.0.0', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ // Enter pre-release mode
+ run('pre enter beta', dir);
+
+ writeFile(
+ dir,
+ '.contractual/changesets/feature.md',
+ `---\n"api": minor\n---\n\n## api\n- Beta feature\n`
+ );
+
+ run('version --yes', dir);
+
+ // Spec should have pre-release version
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toMatch(/^1\.1\.0-beta/);
+
+ // versions.json should match
+ const versions = readJSON(dir, '.contractual/versions.json') as Record<
+ string,
+ { version: string }
+ >;
+ expect(versions['api'].version).toBe(spec.info.version);
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('AsyncAPI', () => {
+ test('updates info.version in AsyncAPI spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'events', type: 'asyncapi', path: 'specs/events.yaml' },
+ ]);
+
+ const asyncSpec = `asyncapi: 2.6.0\ninfo:\n title: Events API\n version: 1.0.0\nchannels: {}\n`;
+ writeFile(dir, 'specs/events.yaml', asyncSpec);
+ writeFile(dir, '.contractual/snapshots/events.yaml', asyncSpec);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({ events: { version: '1.0.0', released: '2026-01-01T00:00:00Z' } })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/event-change.md',
+ `---\n"events": minor\n---\n\n## events\n- Added new channel\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/events.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.1.0');
+
+ // Snapshot too
+ const snapshot = readYAML(dir, '.contractual/snapshots/events.yaml') as {
+ info: { version: string };
+ };
+ expect(snapshot.info.version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('ODCS', () => {
+ test('updates top-level version in ODCS spec', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ setupRepoWithConfig(dir, [
+ { name: 'data-contract', type: 'odcs', path: 'specs/contract.yaml' },
+ ]);
+
+ const odcsSpec = `dataContractSpecification: 3.0.0\nkind: DataContract\nversion: 1.0.0\ninfo:\n title: Sales Data\n`;
+ writeFile(dir, 'specs/contract.yaml', odcsSpec);
+ writeFile(dir, '.contractual/snapshots/data-contract.yaml', odcsSpec);
+
+ writeFile(
+ dir,
+ '.contractual/versions.json',
+ JSON.stringify({
+ 'data-contract': { version: '1.0.0', released: '2026-01-01T00:00:00Z' },
+ })
+ );
+
+ writeFile(
+ dir,
+ '.contractual/changesets/schema-update.md',
+ `---\n"data-contract": minor\n---\n\n## data-contract\n- Added new column\n`
+ );
+
+ run('version', dir);
+
+ const spec = readYAML(dir, 'specs/contract.yaml') as { version: string };
+ expect(spec.version).toBe('1.1.0');
+
+ // Snapshot too
+ const snapshot = readYAML(dir, '.contractual/snapshots/data-contract.yaml') as {
+ version: string;
+ };
+ expect(snapshot.version).toBe('1.1.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+
+ describe('contract add', () => {
+ test('syncs initial version into spec on contract add', () => {
+ const { dir, cleanup } = createTempRepo();
+ try {
+ // Create contractual.yaml with empty contracts
+ writeFile(dir, 'contractual.yaml', 'contracts: []\n');
+ writeFile(dir, '.contractual/versions.json', '{}');
+
+ const specContent = `openapi: 3.0.3\ninfo:\n title: API\n version: 0.0.0\npaths: {}\n`;
+ writeFile(dir, 'specs/api.yaml', specContent);
+
+ run(
+ 'contract add --name my-api --type openapi --path specs/api.yaml --initial-version 1.0.0 --yes --skip-validation',
+ dir
+ );
+
+ // Spec version should be set to 1.0.0
+ const spec = readYAML(dir, 'specs/api.yaml') as { info: { version: string } };
+ expect(spec.info.version).toBe('1.0.0');
+
+ // Snapshot should also have it
+ expect(fileExists(dir, '.contractual/snapshots/my-api.yaml')).toBe(true);
+ const snapshot = readYAML(dir, '.contractual/snapshots/my-api.yaml') as {
+ info: { version: string };
+ };
+ expect(snapshot.info.version).toBe('1.0.0');
+ } finally {
+ cleanup();
+ }
+ });
+ });
+});
diff --git a/tests/e2e/helpers.ts b/tests/e2e/helpers.ts
new file mode 100644
index 0000000..9ff5074
--- /dev/null
+++ b/tests/e2e/helpers.ts
@@ -0,0 +1,308 @@
+import { execSync } from 'node:child_process';
+import {
+ mkdtempSync,
+ cpSync,
+ readFileSync,
+ existsSync,
+ writeFileSync,
+ readdirSync,
+ rmSync,
+ mkdirSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
+
+/** Path to the built CLI binary */
+const CLI_BIN = path.resolve(__dirname, '../../packages/cli/bin/cli.js');
+
+/** Path to the fixtures directory */
+const FIXTURES_DIR = path.resolve(__dirname, '../fixtures');
+
+/**
+ * Create a temp directory that auto-cleans after test
+ */
+export function createTempRepo(): { dir: string; cleanup: () => void } {
+ const dir = mkdtempSync(path.join(tmpdir(), 'contractual-e2e-'));
+
+ return {
+ dir,
+ cleanup: () => {
+ try {
+ rmSync(dir, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ },
+ };
+}
+
+/**
+ * Create a temp directory WITH git initialized (for tests that need git commits)
+ */
+export function createTempGitRepo(): { dir: string; cleanup: () => void } {
+ const dir = mkdtempSync(path.join(tmpdir(), 'contractual-e2e-'));
+
+ // Initialize git repo with explicit error handling
+ try {
+ execSync('git init --initial-branch=main', { cwd: dir, encoding: 'utf-8' });
+ execSync('git config user.email "test@test.com"', { cwd: dir, encoding: 'utf-8' });
+ execSync('git config user.name "Test User"', { cwd: dir, encoding: 'utf-8' });
+ } catch (err) {
+ // Clean up on failure
+ try {
+ rmSync(dir, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ const error = err as Error & { stderr?: string };
+ throw new Error(`Failed to initialize git repo: ${error.message}\n${error.stderr ?? ''}`);
+ }
+
+ // Verify .git directory exists
+ if (!existsSync(path.join(dir, '.git'))) {
+ try {
+ rmSync(dir, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ throw new Error(`Git init succeeded but .git directory not found in ${dir}`);
+ }
+
+ return {
+ dir,
+ cleanup: () => {
+ try {
+ rmSync(dir, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ },
+ };
+}
+
+/**
+ * Run a contractual CLI command in the given directory
+ */
+export function run(
+ command: string,
+ cwd: string,
+ options?: { expectFail?: boolean; env?: Record; timeout?: number }
+): { stdout: string; stderr: string; exitCode: number } {
+ const fullCmd = `node "${CLI_BIN}" ${command}`;
+
+ try {
+ const stdout = execSync(fullCmd, {
+ cwd,
+ encoding: 'utf-8',
+ stdio: ['pipe', 'pipe', 'pipe'],
+ timeout: options?.timeout,
+ env: { ...process.env, ...options?.env, NO_COLOR: '1', FORCE_COLOR: '0' },
+ });
+ return { stdout, stderr: '', exitCode: 0 };
+ } catch (err: unknown) {
+ const error = err as { stdout?: string; stderr?: string; status?: number };
+ if (!options?.expectFail) {
+ // Unexpected failure β include output for debugging
+ throw new Error(
+ `Command failed: ${fullCmd}\n` +
+ `Exit code: ${error.status}\n` +
+ `stdout: ${error.stdout}\n` +
+ `stderr: ${error.stderr}`
+ );
+ }
+ return {
+ stdout: error.stdout ?? '',
+ stderr: error.stderr ?? '',
+ exitCode: error.status ?? 1,
+ };
+ }
+}
+
+/**
+ * Copy fixture files into the temp repo
+ */
+export function copyFixtures(fixtureDir: string, destDir: string): void {
+ const srcDir = path.join(FIXTURES_DIR, fixtureDir);
+ cpSync(srcDir, destDir, { recursive: true });
+}
+
+/**
+ * Copy a single fixture file
+ */
+export function copyFixture(fixturePath: string, destPath: string): void {
+ const src = path.join(FIXTURES_DIR, fixturePath);
+ const destDir = path.dirname(destPath);
+
+ // Ensure destination directory exists
+ if (!existsSync(destDir)) {
+ mkdirSync(destDir, { recursive: true });
+ }
+
+ cpSync(src, destPath);
+}
+
+/**
+ * Read a file from the temp repo
+ */
+export function readFile(repoDir: string, relativePath: string): string {
+ return readFileSync(path.join(repoDir, relativePath), 'utf-8');
+}
+
+/**
+ * Check if a file exists in the temp repo
+ */
+export function fileExists(repoDir: string, relativePath: string): boolean {
+ return existsSync(path.join(repoDir, relativePath));
+}
+
+/**
+ * Write a file in the temp repo
+ */
+export function writeFile(repoDir: string, relativePath: string, content: string): void {
+ const fullPath = path.join(repoDir, relativePath);
+ const dir = path.dirname(fullPath);
+
+ if (!existsSync(dir)) {
+ mkdirSync(dir, { recursive: true });
+ }
+
+ writeFileSync(fullPath, content);
+}
+
+/**
+ * List files in a directory within the temp repo
+ */
+export function listFiles(repoDir: string, relativePath: string): string[] {
+ const fullPath = path.join(repoDir, relativePath);
+ if (!existsSync(fullPath)) return [];
+ return readdirSync(fullPath);
+}
+
+/**
+ * Read and parse JSON from the temp repo
+ */
+export function readJSON(repoDir: string, relativePath: string): unknown {
+ return JSON.parse(readFile(repoDir, relativePath));
+}
+
+/**
+ * Read and parse YAML from the temp repo
+ */
+export function readYAML(repoDir: string, relativePath: string): unknown {
+ const content = readFile(repoDir, relativePath);
+ return parseYaml(content);
+}
+
+/**
+ * Git commit all changes in the temp repo
+ */
+export function gitCommitAll(repoDir: string, message: string): void {
+ // Verify .git directory exists
+ if (!existsSync(path.join(repoDir, '.git'))) {
+ throw new Error(`gitCommitAll: Not a git repository: ${repoDir}`);
+ }
+
+ try {
+ execSync('git add -A', { cwd: repoDir, encoding: 'utf-8' });
+ execSync(`git commit -m "${message}" --allow-empty`, { cwd: repoDir, encoding: 'utf-8' });
+ } catch (err) {
+ const error = err as Error & { stderr?: string; stdout?: string };
+ throw new Error(
+ `gitCommitAll failed in ${repoDir}: ${error.message}\nstderr: ${error.stderr ?? ''}\nstdout: ${error.stdout ?? ''}`
+ );
+ }
+}
+
+/**
+ * Modify a YAML file (read, transform, write back)
+ */
+export function modifyYAML(
+ repoDir: string,
+ relativePath: string,
+ transform: (content: unknown) => unknown
+): void {
+ const content = parseYaml(readFile(repoDir, relativePath));
+ const modified = transform(content);
+ writeFile(repoDir, relativePath, stringifyYaml(modified as Record));
+}
+
+/**
+ * Modify a JSON file (read, transform, write back)
+ */
+export function modifyJSON(
+ repoDir: string,
+ relativePath: string,
+ transform: (content: unknown) => unknown
+): void {
+ const content = readJSON(repoDir, relativePath);
+ const modified = transform(content);
+ writeFile(repoDir, relativePath, JSON.stringify(modified, null, 2) + '\n');
+}
+
+/**
+ * Setup a repo with a contractual.yaml config and .contractual directory
+ */
+export function setupRepoWithConfig(
+ repoDir: string,
+ contracts: Array<{
+ name: string;
+ type: string;
+ path: string;
+ lint?: string | false;
+ breaking?: string | false;
+ syncVersion?: boolean;
+ }>
+): void {
+ const config = {
+ contracts: contracts.map((c) => ({
+ name: c.name,
+ type: c.type,
+ path: c.path,
+ ...(c.lint !== undefined ? { lint: c.lint } : {}),
+ ...(c.breaking !== undefined ? { breaking: c.breaking } : {}),
+ ...(c.syncVersion !== undefined ? { syncVersion: c.syncVersion } : {}),
+ })),
+ };
+
+ writeFile(repoDir, 'contractual.yaml', stringifyYaml(config));
+
+ // Create .contractual directory structure
+ mkdirSync(path.join(repoDir, '.contractual/changesets'), { recursive: true });
+ mkdirSync(path.join(repoDir, '.contractual/snapshots'), { recursive: true });
+
+ if (!fileExists(repoDir, '.contractual/versions.json')) {
+ writeFile(repoDir, '.contractual/versions.json', '{}');
+ }
+}
+
+/**
+ * Check if oasdiff is available on the system
+ */
+export function checkOasdiff(): boolean {
+ try {
+ execSync('oasdiff --version', { stdio: 'pipe' });
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+/**
+ * Ensure CLI is built before running tests
+ */
+export function ensureCliBuilt(): void {
+ if (!existsSync(CLI_BIN)) {
+ throw new Error(
+ `CLI binary not found at ${CLI_BIN}. Run 'pnpm build' in the root directory first.`
+ );
+ }
+
+ // Also check that the dist directory has the commands.js file
+ const commandsPath = path.resolve(__dirname, '../../packages/cli/dist/commands.js');
+ if (!existsSync(commandsPath)) {
+ throw new Error(
+ `CLI not built properly. dist/commands.js not found. Run 'pnpm build' in the root directory.`
+ );
+ }
+}
diff --git a/tests/fixtures/json-schema/order-additional-props-denied.json b/tests/fixtures/json-schema/order-additional-props-denied.json
new file mode 100644
index 0000000..a59cf5f
--- /dev/null
+++ b/tests/fixtures/json-schema/order-additional-props-denied.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": false
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-base.json b/tests/fixtures/json-schema/order-base.json
new file mode 100644
index 0000000..cec8f1b
--- /dev/null
+++ b/tests/fixtures/json-schema/order-base.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-constraint-tightened.json b/tests/fixtures/json-schema/order-constraint-tightened.json
new file mode 100644
index 0000000..4b94b01
--- /dev/null
+++ b/tests/fixtures/json-schema/order-constraint-tightened.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 5
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 200
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-description-changed.json b/tests/fixtures/json-schema/order-description-changed.json
new file mode 100644
index 0000000..86de9a2
--- /dev/null
+++ b/tests/fixtures/json-schema/order-description-changed.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the e-commerce system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier (UUID format)"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status in the fulfillment pipeline"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-enum-value-added.json b/tests/fixtures/json-schema/order-enum-value-added.json
new file mode 100644
index 0000000..99e03b4
--- /dev/null
+++ b/tests/fixtures/json-schema/order-enum-value-added.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered", "cancelled"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-enum-value-removed.json b/tests/fixtures/json-schema/order-enum-value-removed.json
new file mode 100644
index 0000000..7c836a9
--- /dev/null
+++ b/tests/fixtures/json-schema/order-enum-value-removed.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-field-removed.json b/tests/fixtures/json-schema/order-field-removed.json
new file mode 100644
index 0000000..4b8cb38
--- /dev/null
+++ b/tests/fixtures/json-schema/order-field-removed.json
@@ -0,0 +1,84 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-identical.json b/tests/fixtures/json-schema/order-identical.json
new file mode 100644
index 0000000..cec8f1b
--- /dev/null
+++ b/tests/fixtures/json-schema/order-identical.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-optional-field-added.json b/tests/fixtures/json-schema/order-optional-field-added.json
new file mode 100644
index 0000000..bb1166e
--- /dev/null
+++ b/tests/fixtures/json-schema/order-optional-field-added.json
@@ -0,0 +1,93 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ },
+ "tracking_number": {
+ "type": "string",
+ "description": "Shipment tracking number"
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-required-added.json b/tests/fixtures/json-schema/order-required-added.json
new file mode 100644
index 0000000..249e0b3
--- /dev/null
+++ b/tests/fixtures/json-schema/order-required-added.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "string",
+ "description": "Order total amount as string"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at", "customer_email"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/json-schema/order-type-changed.json b/tests/fixtures/json-schema/order-type-changed.json
new file mode 100644
index 0000000..c9c585a
--- /dev/null
+++ b/tests/fixtures/json-schema/order-type-changed.json
@@ -0,0 +1,89 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.com/order.schema.json",
+ "title": "Order",
+ "description": "An order in the system",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique order identifier"
+ },
+ "status": {
+ "type": "string",
+ "enum": ["pending", "processing", "shipped", "delivered"],
+ "description": "Current order status"
+ },
+ "amount": {
+ "type": "number",
+ "description": "Order total amount as number"
+ },
+ "currency": {
+ "type": "string",
+ "format": "iso-4217",
+ "description": "Currency code (ISO 4217)"
+ },
+ "items": {
+ "type": "array",
+ "description": "Line items in the order",
+ "items": {
+ "type": "object",
+ "properties": {
+ "sku": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "price": {
+ "type": "string"
+ }
+ },
+ "required": ["sku", "quantity", "price"]
+ }
+ },
+ "shipping_address": {
+ "type": "object",
+ "description": "Shipping address",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "zip": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": ["street", "city", "zip", "country"]
+ },
+ "customer_email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email address"
+ },
+ "notes": {
+ "type": "string",
+ "description": "Optional order notes",
+ "maxLength": 500
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Order creation timestamp"
+ },
+ "metadata": {
+ "type": "object",
+ "description": "Additional metadata",
+ "additionalProperties": true
+ }
+ },
+ "required": ["id", "status", "amount", "currency", "items", "created_at"],
+ "additionalProperties": false
+}
diff --git a/tests/fixtures/openapi/circular-refs-base.yaml b/tests/fixtures/openapi/circular-refs-base.yaml
new file mode 100644
index 0000000..ebfbcd7
--- /dev/null
+++ b/tests/fixtures/openapi/circular-refs-base.yaml
@@ -0,0 +1,60 @@
+openapi: 3.1.0
+info:
+ title: Circular Refs API
+ version: 1.0.0
+paths:
+ /categories:
+ get:
+ operationId: listCategories
+ summary: List categories (tree structure with circular refs)
+ responses:
+ "200":
+ description: A list of categories
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Category'
+ /nodes:
+ get:
+ operationId: listNodes
+ summary: List nodes (linked list with circular refs)
+ responses:
+ "200":
+ description: A list of nodes
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Node'
+components:
+ schemas:
+ Category:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+ parent:
+ $ref: '#/components/schemas/Category'
+ children:
+ type: array
+ items:
+ $ref: '#/components/schemas/Category'
+ Node:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ value:
+ type: string
+ next:
+ $ref: '#/components/schemas/Node'
diff --git a/tests/fixtures/openapi/circular-refs-breaking.yaml b/tests/fixtures/openapi/circular-refs-breaking.yaml
new file mode 100644
index 0000000..a0a0463
--- /dev/null
+++ b/tests/fixtures/openapi/circular-refs-breaking.yaml
@@ -0,0 +1,61 @@
+openapi: 3.1.0
+info:
+ title: Circular Refs API
+ version: 1.0.0
+paths:
+ /categories:
+ get:
+ operationId: listCategories
+ summary: List categories (tree structure with circular refs)
+ responses:
+ "200":
+ description: A list of categories
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Category'
+ /nodes:
+ get:
+ operationId: listNodes
+ summary: List nodes (linked list with circular refs)
+ responses:
+ "200":
+ description: A list of nodes
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Node'
+components:
+ schemas:
+ Category:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ # BREAKING: changed from integer to string
+ type: string
+ name:
+ type: string
+ parent:
+ $ref: '#/components/schemas/Category'
+ children:
+ type: array
+ items:
+ $ref: '#/components/schemas/Category'
+ Node:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ value:
+ type: string
+ next:
+ $ref: '#/components/schemas/Node'
diff --git a/tests/fixtures/openapi/petstore-31-base.yaml b/tests/fixtures/openapi/petstore-31-base.yaml
new file mode 100644
index 0000000..0cace6b
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-base.yaml
@@ -0,0 +1,103 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-breaking-endpoint-removed.yaml b/tests/fixtures/openapi/petstore-31-breaking-endpoint-removed.yaml
new file mode 100644
index 0000000..14b3ea0
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-breaking-endpoint-removed.yaml
@@ -0,0 +1,85 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ # BREAKING: /pets/{petId} path removed entirely
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-breaking-required-param.yaml b/tests/fixtures/openapi/petstore-31-breaking-required-param.yaml
new file mode 100644
index 0000000..f0f6191
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-breaking-required-param.yaml
@@ -0,0 +1,109 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ # BREAKING: new required query parameter
+ - name: apiKey
+ in: query
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-breaking-type-narrowed.yaml b/tests/fixtures/openapi/petstore-31-breaking-type-narrowed.yaml
new file mode 100644
index 0000000..9b57ab5
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-breaking-type-narrowed.yaml
@@ -0,0 +1,102 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ # BREAKING: narrowed from ["string", "null"] to just "string" β null no longer allowed
+ type: string
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-description-changed.yaml b/tests/fixtures/openapi/petstore-31-description-changed.yaml
new file mode 100644
index 0000000..552b3b9
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-description-changed.yaml
@@ -0,0 +1,107 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ # CHANGED: description updated
+ summary: An updated sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ # CHANGED: operation summary updated
+ summary: List all available pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ # CHANGED: operation description added
+ description: Creates a new pet in the store. Requires a valid pet name.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-nonbreaking-optional-param.yaml b/tests/fixtures/openapi/petstore-31-nonbreaking-optional-param.yaml
new file mode 100644
index 0000000..14954d6
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-nonbreaking-optional-param.yaml
@@ -0,0 +1,109 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ # NON-BREAKING: new optional query parameter
+ - name: offset
+ in: query
+ required: false
+ schema:
+ type: integer
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-31-nonbreaking-type-widened.yaml b/tests/fixtures/openapi/petstore-31-nonbreaking-type-widened.yaml
new file mode 100644
index 0000000..b26efd3
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-31-nonbreaking-type-widened.yaml
@@ -0,0 +1,106 @@
+openapi: 3.1.0
+info:
+ title: Petstore - OpenAPI 3.1
+ summary: A sample petstore using OpenAPI 3.1 features
+ license:
+ name: MIT
+ identifier: MIT
+ version: 1.0.0
+jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
+servers:
+- url: /api/v3
+paths:
+ /pets:
+ get:
+ operationId: listPets
+ summary: List all pets
+ parameters:
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ exclusiveMaximum: 100
+ responses:
+ "200":
+ description: A list of pets
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ default:
+ description: unexpected error
+ post:
+ operationId: createPet
+ summary: Create a pet
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/NewPet'
+ responses:
+ "201":
+ description: Pet created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ /pets/{petId}:
+ get:
+ operationId: getPetById
+ summary: Get a pet by ID
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: A pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "404":
+ description: Pet not found
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ # NON-BREAKING: widened from integer to [integer, string]
+ type:
+ - integer
+ - string
+ format: int64
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
+ status:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ NewPet:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ tag:
+ type:
+ - string
+ - "null"
diff --git a/tests/fixtures/openapi/petstore-base.yaml b/tests/fixtures/openapi/petstore-base.yaml
new file mode 100644
index 0000000..de3d03c
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-base.yaml
@@ -0,0 +1,830 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
+ You can now help us improve the API whether it's by making changes to the definition itself or to the code.
+ That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+
+ Some useful links:
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags.
+ description: "Multiple tags can be provided with comma separated strings. Use\
+ \ tag1, tag2, tag3 for testing."
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid tag value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/openapi/petstore-breaking-endpoint-removed.yaml b/tests/fixtures/openapi/petstore-breaking-endpoint-removed.yaml
new file mode 100644
index 0000000..ae1b38e
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-breaking-endpoint-removed.yaml
@@ -0,0 +1,790 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
+ You can now help us improve the API whether it's by making changes to the definition itself or to the code.
+ That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+
+ Some useful links:
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/openapi/petstore-breaking-type-changed.yaml b/tests/fixtures/openapi/petstore-breaking-type-changed.yaml
new file mode 100644
index 0000000..615ff40
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-breaking-type-changed.yaml
@@ -0,0 +1,829 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
+ You can now help us improve the API whether it's by making changes to the definition itself or to the code.
+ That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+
+ Some useful links:
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags.
+ description: "Multiple tags can be provided with comma separated strings. Use\
+ \ tag1, tag2, tag3 for testing."
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid tag value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: string
+ example: "10"
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/openapi/petstore-identical.yaml b/tests/fixtures/openapi/petstore-identical.yaml
new file mode 100644
index 0000000..de3d03c
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-identical.yaml
@@ -0,0 +1,830 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
+ You can now help us improve the API whether it's by making changes to the definition itself or to the code.
+ That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+
+ Some useful links:
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags.
+ description: "Multiple tags can be provided with comma separated strings. Use\
+ \ tag1, tag2, tag3 for testing."
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid tag value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/openapi/petstore-nonbreaking-description.yaml b/tests/fixtures/openapi/petstore-nonbreaking-description.yaml
new file mode 100644
index 0000000..8901a5c
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-nonbreaking-description.yaml
@@ -0,0 +1,830 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). We've switched to the design first approach!
+ Help us improve the API by making changes to the definition itself or to the code.
+ Over time, we can improve the API and expose new features in OAS3.
+
+ Useful links:
+ - [Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [Source API definition](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags.
+ description: "Multiple tags can be provided with comma separated strings. Use\
+ \ tag1, tag2, tag3 for testing."
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid tag value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/openapi/petstore-nonbreaking-endpoint-added.yaml b/tests/fixtures/openapi/petstore-nonbreaking-endpoint-added.yaml
new file mode 100644
index 0000000..46599cf
--- /dev/null
+++ b/tests/fixtures/openapi/petstore-nonbreaking-endpoint-added.yaml
@@ -0,0 +1,856 @@
+openapi: 3.0.3
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: |-
+ This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
+ Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
+ You can now help us improve the API whether it's by making changes to the definition itself or to the code.
+ That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+
+ Some useful links:
+ - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
+ - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
+ termsOfService: https://swagger.io/terms/
+ contact:
+ email: apiteam@swagger.io
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.27
+externalDocs:
+ description: Find out more about Swagger
+ url: https://swagger.io
+servers:
+- url: /api/v3
+tags:
+- name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: https://swagger.io
+- name: store
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: https://swagger.io
+- name: user
+ description: Operations about user
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet.
+ description: Update an existing pet by Id.
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store.
+ description: Add a new pet to the store.
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status.
+ description: Multiple status values can be provided with comma separated strings.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid status value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags.
+ description: "Multiple tags can be provided with comma separated strings. Use\
+ \ tag1, tag2, tag3 for testing."
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid tag value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}:
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID.
+ description: Returns a single pet.
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data.
+ description: Updates a pet resource based on the form data.
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid input
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet.
+ description: Delete a pet.
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: Pet deleted
+ "400":
+ description: Invalid pet value
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/{petId}/uploadImage:
+ post:
+ tags:
+ - pet
+ summary: Uploads an image.
+ description: Upload image of the pet.
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ "400":
+ description: No file uploaded
+ "404":
+ description: Pet not found
+ default:
+ description: Unexpected error
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ /pet/health:
+ get:
+ tags:
+ - pet
+ summary: Check pet service health.
+ description: Returns the health status of the pet service.
+ operationId: getPetHealth
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum:
+ - healthy
+ - degraded
+ - unhealthy
+ timestamp:
+ type: string
+ format: date-time
+ default:
+ description: Unexpected error
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status.
+ description: Returns a map of status codes to quantities.
+ operationId: getInventory
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ default:
+ description: Unexpected error
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet.
+ description: Place a new order in the store.
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid input
+ "422":
+ description: Validation exception
+ default:
+ description: Unexpected error
+ /store/order/{orderId}:
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID.
+ description: For valid response try integer IDs with value <= 5 or > 10. Other
+ values will generate exceptions.
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by identifier.
+ description: For valid response try integer IDs with value < 1000. Anything
+ above 1000 or non-integers will generate API errors.
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: order deleted
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Order not found
+ default:
+ description: Unexpected error
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user.
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array.
+ description: Creates list of users with given input array.
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: Unexpected error
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system.
+ description: Log into the system.
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when token expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ default:
+ description: Unexpected error
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session.
+ description: Log user out of the system.
+ operationId: logoutUser
+ parameters: []
+ responses:
+ "200":
+ description: successful operation
+ default:
+ description: Unexpected error
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name.
+ description: Get user detail based on username.
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+ put:
+ tags:
+ - user
+ summary: Update user resource.
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: successful operation
+ "400":
+ description: bad request
+ "404":
+ description: user not found
+ default:
+ description: Unexpected error
+ delete:
+ tags:
+ - user
+ summary: Delete user resource.
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: User deleted
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ default:
+ description: Unexpected error
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: john@email.com
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: pet
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/tests/fixtures/tool-outputs/oasdiff/breaking-endpoint-removed.json b/tests/fixtures/tool-outputs/oasdiff/breaking-endpoint-removed.json
new file mode 100644
index 0000000..42f0e6c
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/breaking-endpoint-removed.json
@@ -0,0 +1 @@
+[{"id":"api-path-removed-without-deprecation","text":"api path removed without deprecation","level":3,"operation":"GET","operationId":"findPetsByTags","path":"/pet/findByTags","source":"openapi/petstore-base.yaml","section":"paths"}]
diff --git a/tests/fixtures/tool-outputs/oasdiff/breaking-type-changed.json b/tests/fixtures/tool-outputs/oasdiff/breaking-type-changed.json
new file mode 100644
index 0000000..94f6cf3
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/breaking-type-changed.json
@@ -0,0 +1 @@
+[{"id":"request-property-type-changed","text":"the 'id' request property type/format changed from 'integer'/'int64' to 'string'/'' (media type: application/json)","level":3,"operation":"POST","operationId":"placeOrder","path":"/store/order","source":"openapi/petstore-breaking-type-changed.yaml","section":"paths"},{"id":"response-property-type-changed","text":"the 'id' response's property type/format changed from 'integer'/'int64' to 'string'/'' for status '200'","level":3,"operation":"POST","operationId":"placeOrder","path":"/store/order","source":"openapi/petstore-breaking-type-changed.yaml","section":"paths"},{"id":"response-property-type-changed","text":"the 'id' response's property type/format changed from 'integer'/'int64' to 'string'/'' for status '200' (media type: application/xml)","level":3,"operation":"GET","operationId":"getOrderById","path":"/store/order/{orderId}","source":"openapi/petstore-breaking-type-changed.yaml","section":"paths"},{"id":"response-property-type-changed","text":"the 'id' response's property type/format changed from 'integer'/'int64' to 'string'/'' for status '200' (media type: application/json)","level":3,"operation":"GET","operationId":"getOrderById","path":"/store/order/{orderId}","source":"openapi/petstore-breaking-type-changed.yaml","section":"paths"}]
diff --git a/tests/fixtures/tool-outputs/oasdiff/changelog-endpoint-removed.json b/tests/fixtures/tool-outputs/oasdiff/changelog-endpoint-removed.json
new file mode 100644
index 0000000..42f0e6c
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/changelog-endpoint-removed.json
@@ -0,0 +1 @@
+[{"id":"api-path-removed-without-deprecation","text":"api path removed without deprecation","level":3,"operation":"GET","operationId":"findPetsByTags","path":"/pet/findByTags","source":"openapi/petstore-base.yaml","section":"paths"}]
diff --git a/tests/fixtures/tool-outputs/oasdiff/diff-endpoint-removed.json b/tests/fixtures/tool-outputs/oasdiff/diff-endpoint-removed.json
new file mode 100644
index 0000000..59bdd3a
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/diff-endpoint-removed.json
@@ -0,0 +1 @@
+{"paths":{"deleted":["/pet/findByTags"]}}
diff --git a/tests/fixtures/tool-outputs/oasdiff/no-changes.json b/tests/fixtures/tool-outputs/oasdiff/no-changes.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/no-changes.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/fixtures/tool-outputs/oasdiff/nonbreaking-endpoint-added.json b/tests/fixtures/tool-outputs/oasdiff/nonbreaking-endpoint-added.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/tests/fixtures/tool-outputs/oasdiff/nonbreaking-endpoint-added.json
@@ -0,0 +1 @@
+[]
diff --git a/tsconfig.build.json b/tsconfig.build.json
index 32971be..5ea453e 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -1,10 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
- "target": "esnext",
- "module": "esnext",
- "moduleResolution": "node",
- "incremental": false,
"sourceMap": false
},
"exclude": [
diff --git a/tsconfig.json b/tsconfig.json
index 26aa473..33aeced 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,19 +1,19 @@
{
"compilerOptions": {
- "module": "esnext",
- "target": "esnext",
- "skipLibCheck": true,
+ "module": "NodeNext",
+ "target": "ES2022",
+ "moduleResolution": "NodeNext",
"declaration": true,
+ "declarationMap": true,
+ "skipLibCheck": true,
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"baseUrl": "./",
"outDir": "./dist",
- "incremental": false,
"noImplicitAny": true,
"strictNullChecks": true,
- "moduleResolution": "node",
"esModuleInterop": true,
"resolveJsonModule": true,
"types": [
diff --git a/vitest.config.e2e.ts b/vitest.config.e2e.ts
new file mode 100644
index 0000000..166305d
--- /dev/null
+++ b/vitest.config.e2e.ts
@@ -0,0 +1,18 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['tests/e2e/**/*.test.ts'],
+ testTimeout: 60_000,
+ hookTimeout: 30_000,
+ teardownTimeout: 30_000,
+ // Run serially β each test creates temp dirs, parallel risks port/path conflicts
+ fileParallelism: false,
+ globals: true,
+ server: {
+ deps: {
+ inline: ['yaml'],
+ },
+ },
+ },
+});