diff --git a/.github/workflows/ci-server-reusable.yml b/.github/workflows/ci-server-reusable.yml new file mode 100644 index 0000000..10ba3c6 --- /dev/null +++ b/.github/workflows/ci-server-reusable.yml @@ -0,0 +1,159 @@ +name: Server CI Reusable + +on: + workflow_call: + inputs: + job_name: + required: true + type: string + build_script: + required: true + type: string + test_script: + required: true + type: string + test_working_directory: + required: true + type: string + run_integration_tests: + required: false + default: false + type: boolean + integration_test_script: + required: false + default: "" + type: string + integration_test_working_directory: + required: false + default: "" + type: string + dockerfile: + required: true + type: string + image_ref: + required: true + type: string + trivy_results_file: + required: true + type: string + trivy_sarif_file: + required: true + type: string + trivy_scan_label: + required: true + type: string + sarif_category: + required: true + type: string + +jobs: + server: + name: ${{ inputs.job_name }} + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Use Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: npm + cache-dependency-path: package-lock.json + + - name: Install dependencies (monorepo) + run: npm ci --workspaces + + - name: Build shared package + run: npm run build:shared + + - name: Build target server + run: ${{ inputs.build_script }} + + - name: Run tests + run: ${{ inputs.test_script }} + working-directory: ${{ inputs.test_working_directory }} + + - name: Run integration tests + if: inputs.run_integration_tests + run: ${{ inputs.integration_test_script }} + working-directory: ${{ inputs.integration_test_working_directory }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image for scanning + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ inputs.dockerfile }} + load: true + tags: ${{ inputs.image_ref }} + build-args: | + BUILD_NUMBER=${{ github.run_number }} + + - name: Scan image for HIGH and CRITICAL vulnerabilities + id: trivy_scan + continue-on-error: true + uses: aquasecurity/trivy-action@v0.35.0 + with: + image-ref: ${{ inputs.image_ref }} + format: table + output: ${{ inputs.trivy_results_file }} + ignore-unfixed: true + severity: HIGH,CRITICAL + exit-code: '1' + + - name: Add Trivy report to job summary + if: always() + run: | + { + echo "## ${{ inputs.trivy_scan_label }}" + echo + if [ "${{ steps.trivy_scan.outcome }}" = "failure" ]; then + echo "**Status:** FAILED (HIGH/CRITICAL vulnerabilities found)" + else + echo "**Status:** PASSED (no HIGH/CRITICAL vulnerabilities found)" + fi + echo + echo "
Full Trivy output" + echo + echo '```text' + cat "${{ inputs.trivy_results_file }}" + echo '```' + echo "
" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Generate Trivy SARIF report + if: always() + uses: aquasecurity/trivy-action@v0.35.0 + with: + image-ref: ${{ inputs.image_ref }} + format: sarif + output: ${{ inputs.trivy_sarif_file }} + ignore-unfixed: true + severity: HIGH,CRITICAL + exit-code: '0' + + - name: Upload Trivy SARIF to GitHub Security + id: trivy_sarif_upload + continue-on-error: true + if: always() + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: ${{ inputs.trivy_sarif_file }} + category: ${{ inputs.sarif_category }} + + - name: Add SARIF upload status to job summary + if: always() && steps.trivy_sarif_upload.outcome == 'failure' + run: | + echo >> "$GITHUB_STEP_SUMMARY" + echo "## SARIF Upload" >> "$GITHUB_STEP_SUMMARY" + echo >> "$GITHUB_STEP_SUMMARY" + echo "SARIF upload was skipped or failed. GitHub code scanning may not be enabled for this repository." >> "$GITHUB_STEP_SUMMARY" + + - name: Fail job if Trivy found HIGH/CRITICAL issues + if: steps.trivy_scan.outcome == 'failure' + run: | + echo "Trivy detected HIGH/CRITICAL vulnerabilities. See job summary and Security tab for details." + exit 1 diff --git a/.github/workflows/ci-shared.yml b/.github/workflows/ci-shared.yml new file mode 100644 index 0000000..f94585f --- /dev/null +++ b/.github/workflows/ci-shared.yml @@ -0,0 +1,44 @@ +name: Shared Package CI + +on: + pull_request: + paths: + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - '.github/workflows/ci-shared.yml' + push: + branches: + - master + paths: + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - '.github/workflows/ci-shared.yml' + +jobs: + shared: + name: Build and Test mcp-shared + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Use Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: npm + cache-dependency-path: package-lock.json + + - name: Install dependencies (monorepo) + run: npm ci --workspaces + + - name: Build shared package + run: npm run build:shared + + - name: Run tests (mcp-shared) + run: npm run test -- --run + working-directory: packages/mcp-shared diff --git a/.github/workflows/ci-wallet.yml b/.github/workflows/ci-wallet.yml new file mode 100644 index 0000000..0913001 --- /dev/null +++ b/.github/workflows/ci-wallet.yml @@ -0,0 +1,45 @@ +name: Wallet CI + +on: + pull_request: + paths: + - 'apps/wallet-server/**' + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' + - '.github/workflows/ci-wallet.yml' + - '.github/workflows/ci-server-reusable.yml' + push: + branches: + - master + paths: + - 'apps/wallet-server/**' + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' + - '.github/workflows/ci-wallet.yml' + - '.github/workflows/ci-server-reusable.yml' + +jobs: + wallet: + uses: ./.github/workflows/ci-server-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + job_name: Build and Test Wallet Server + build_script: npm run build:wallet + test_script: npm test + test_working_directory: apps/wallet-server + run_integration_tests: true + integration_test_script: npm run test:integration + integration_test_working_directory: apps/wallet-server + dockerfile: ./apps/wallet-server/Dockerfile + image_ref: truvera-wallet-mcp:ci + trivy_results_file: wallet-trivy-results.txt + trivy_sarif_file: wallet-trivy-results.sarif + trivy_scan_label: Wallet Trivy Image Scan + sarif_category: trivy-container-scan-wallet diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61c5ef4..bb4866e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,130 +1,46 @@ -name: CI +name: API CI on: pull_request: + paths: + - 'apps/truvera-api/**' + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' + - '.github/workflows/ci.yml' + - '.github/workflows/ci-server-reusable.yml' push: branches: - master - + paths: + - 'apps/truvera-api/**' + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' + - '.github/workflows/ci.yml' + - '.github/workflows/ci-server-reusable.yml' + jobs: - build: - name: Build and Test - runs-on: ubuntu-latest + api: + uses: ./.github/workflows/ci-server-reusable.yml permissions: actions: read contents: read security-events: write - strategy: - matrix: - node-version: [22.x] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - cache-dependency-path: 'package-lock.json' - - - name: Install dependencies (monorepo) - run: npm ci --workspaces - - - name: Build shared package - run: npm run build:shared - - - name: Build truvera-api - run: npm run build:api - - - name: Build wallet-server - run: npm run build --workspace=apps/wallet-server - - - name: Run tests (truvera-api) - run: npm run test -- --run - working-directory: apps/truvera-api - - - name: Run tests (mcp-shared) - run: npm run test -- --run - working-directory: packages/mcp-shared - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build truvera-api image for scanning - uses: docker/build-push-action@v6 - with: - context: . - file: ./apps/truvera-api/Dockerfile - load: true - tags: truvera-api-mcp:ci - build-args: | - BUILD_NUMBER=${{ github.run_number }} - - - name: Scan truvera-api image for HIGH and CRITICAL vulnerabilities - id: trivy_scan - continue-on-error: true - uses: aquasecurity/trivy-action@v0.35.0 - with: - image-ref: truvera-api-mcp:ci - format: table - output: trivy-results.txt - ignore-unfixed: true - severity: HIGH,CRITICAL - exit-code: '1' - - - name: Add Trivy report to job summary - if: always() - run: | - { - echo "## Trivy Image Scan" - echo - if [ "${{ steps.trivy_scan.outcome }}" = "failure" ]; then - echo "**Status:** FAILED (HIGH/CRITICAL vulnerabilities found)" - else - echo "**Status:** PASSED (no HIGH/CRITICAL vulnerabilities found)" - fi - echo - echo "
Full Trivy output" - echo - echo '```text' - cat trivy-results.txt - echo '```' - echo "
" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Generate Trivy SARIF report - if: always() - uses: aquasecurity/trivy-action@v0.35.0 - with: - image-ref: truvera-api-mcp:ci - format: sarif - output: trivy-results.sarif - ignore-unfixed: true - severity: HIGH,CRITICAL - exit-code: '0' - - - name: Upload Trivy SARIF to GitHub Security - id: trivy_sarif_upload - continue-on-error: true - if: always() - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: trivy-results.sarif - category: trivy-container-scan - - - name: Add SARIF upload status to job summary - if: always() - run: | - if [ "${{ steps.trivy_sarif_upload.outcome }}" = "failure" ]; then - echo >> "$GITHUB_STEP_SUMMARY" - echo "## SARIF Upload" >> "$GITHUB_STEP_SUMMARY" - echo >> "$GITHUB_STEP_SUMMARY" - echo "SARIF upload was skipped or failed. GitHub code scanning may not be enabled for this repository." >> "$GITHUB_STEP_SUMMARY" - fi + with: + job_name: Build and Test API Server + build_script: npm run build:api + test_script: npm run test -- --run + test_working_directory: apps/truvera-api + run_integration_tests: false + integration_test_script: "" + integration_test_working_directory: "" + dockerfile: ./apps/truvera-api/Dockerfile + image_ref: truvera-api-mcp:ci + trivy_results_file: trivy-results.txt + trivy_sarif_file: trivy-results.sarif + trivy_scan_label: API Trivy Image Scan + sarif_category: trivy-container-scan-api - - name: Fail job if Trivy found HIGH/CRITICAL issues - if: steps.trivy_scan.outcome == 'failure' - run: | - echo "Trivy detected HIGH/CRITICAL vulnerabilities. See job summary and Security tab for details." - exit 1 diff --git a/.github/workflows/docker-publish-reusable.yml b/.github/workflows/docker-publish-reusable.yml new file mode 100644 index 0000000..2f25dea --- /dev/null +++ b/.github/workflows/docker-publish-reusable.yml @@ -0,0 +1,90 @@ +name: Docker Publish Reusable + +on: + workflow_call: + inputs: + docker_image: + required: true + type: string + dockerfile: + required: true + type: string + build_number_file: + required: true + type: string + should_push: + required: true + type: boolean + +jobs: + publish: + name: Build and Publish Image + runs-on: ubuntu-latest + env: + DOCKER_IMAGE: ${{ inputs.docker_image }} + DOCKERFILE: ${{ inputs.dockerfile }} + BUILD_NUMBER_FILE: ${{ inputs.build_number_file }} + SHOULD_PUSH: ${{ inputs.should_push }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Read build number + id: build_number + run: | + if [ -f "${BUILD_NUMBER_FILE}" ]; then + BUILD_NUM=$(cat "${BUILD_NUMBER_FILE}") + echo "Using ${BUILD_NUMBER_FILE}" + else + BUILD_NUM="${{ github.run_number }}" + echo "${BUILD_NUMBER_FILE} not found; using GitHub run number" + fi + echo "build_number=$BUILD_NUM" >> "$GITHUB_OUTPUT" + echo "Build number: $BUILD_NUM" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to DockerHub + if: ${{ env.SHOULD_PUSH == 'true' }} + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKER_IMAGE }} + tags: | + type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.release.target_commitish == github.event.repository.default_branch }} + type=raw,value=${{ steps.build_number.outputs.build_number }} + labels: | + org.opencontainers.image.licenses=LicenseRef-DL-NPL + + - name: Build and publish Docker image + id: docker_build + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ env.DOCKERFILE }} + push: ${{ env.SHOULD_PUSH == 'true' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + sbom: ${{ env.SHOULD_PUSH == 'true' }} + provenance: ${{ env.SHOULD_PUSH == 'true' }} + build-args: | + BUILD_NUMBER=${{ steps.build_number.outputs.build_number }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + + - name: Image digest + if: ${{ env.SHOULD_PUSH == 'true' }} + run: echo "Image pushed with digest ${{ steps.docker_build.outputs.digest }}" + + - name: Image build only + if: ${{ env.SHOULD_PUSH != 'true' }} + run: echo "Image built without push because workflow_dispatch input 'push' was false" diff --git a/.github/workflows/docker-publish-wallet.yml b/.github/workflows/docker-publish-wallet.yml new file mode 100644 index 0000000..13e14ea --- /dev/null +++ b/.github/workflows/docker-publish-wallet.yml @@ -0,0 +1,36 @@ +name: Publish Wallet Docker Image + +on: + push: + branches: + - master + paths: + - 'apps/wallet-server/**' + - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' + - '.github/workflows/docker-publish-wallet.yml' + - '.github/workflows/docker-publish-reusable.yml' + release: + types: [published] + workflow_dispatch: + inputs: + push: + description: Push image to DockerHub + required: false + default: true + type: boolean + +jobs: + wallet: + uses: ./.github/workflows/docker-publish-reusable.yml + permissions: + contents: read + packages: write + id-token: write + with: + docker_image: docknetwork/truvera-wallet-mcp + dockerfile: ./apps/wallet-server/Dockerfile + build_number_file: apps/wallet-server/.buildnumber + should_push: ${{ github.event_name != 'workflow_dispatch' || inputs.push }} diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 54dfb2d..e261211 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,4 +1,4 @@ -name: Build and Push Docker Images +name: Publish API Docker Image on: push: @@ -7,91 +7,30 @@ on: paths: - 'apps/truvera-api/**' - 'packages/mcp-shared/**' + - 'package.json' + - 'package-lock.json' + - 'scripts/**' - '.github/workflows/docker-publish.yml' - + - '.github/workflows/docker-publish-reusable.yml' release: types: [published] - workflow_dispatch: inputs: push: - description: 'Push images to DockerHub' + description: Push image to DockerHub required: false default: true type: boolean jobs: - build-and-push: - name: Build and Push truvera-api-mcp - runs-on: ubuntu-latest - env: - SHOULD_PUSH: ${{ github.event_name != 'workflow_dispatch' || inputs.push }} - DOCKER_IMAGE: docknetwork/truvera-api-mcp + api: + uses: ./.github/workflows/docker-publish-reusable.yml permissions: contents: read packages: write id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Read build number - id: build_number - run: | - if [ -f apps/truvera-api/.buildnumber ]; then - BUILD_NUM=$(cat apps/truvera-api/.buildnumber) - echo "Using apps/truvera-api/.buildnumber" - else - BUILD_NUM="${{ github.run_number }}" - echo "apps/truvera-api/.buildnumber not found; using GitHub run number" - fi - echo "build_number=$BUILD_NUM" >> $GITHUB_OUTPUT - echo "Build number: $BUILD_NUM" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to DockerHub - if: ${{ env.SHOULD_PUSH == 'true' }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - - - name: Extract metadata for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.DOCKER_IMAGE }} - tags: | - type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.release.target_commitish == github.event.repository.default_branch }} - type=raw,value=${{ steps.build_number.outputs.build_number }} - labels: | - org.opencontainers.image.licenses=LicenseRef-DL-NPL - - - name: Build and push API Docker image - id: docker_build - uses: docker/build-push-action@v6 - with: - context: . - file: ./apps/truvera-api/Dockerfile - push: ${{ env.SHOULD_PUSH == 'true' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - sbom: ${{ env.SHOULD_PUSH == 'true' }} - provenance: ${{ env.SHOULD_PUSH == 'true' }} - build-args: | - BUILD_NUMBER=${{ steps.build_number.outputs.build_number }} - cache-from: type=gha - cache-to: type=gha,mode=max - platforms: linux/amd64,linux/arm64 - - - name: Image digest - if: ${{ env.SHOULD_PUSH == 'true' }} - run: echo "Image pushed with digest ${{ steps.docker_build.outputs.digest }}" - - - name: Image build only - if: ${{ env.SHOULD_PUSH != 'true' }} - run: echo "Image built without push because workflow_dispatch input 'push' was false" + with: + docker_image: docknetwork/truvera-api-mcp + dockerfile: ./apps/truvera-api/Dockerfile + build_number_file: apps/truvera-api/.buildnumber + should_push: ${{ github.event_name != 'workflow_dispatch' || inputs.push }} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c74bf16..0dde2a8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -25,6 +25,27 @@ }, "isBackground": true, "problemMatcher": [] + }, + { + "label": "build:wallet", + "type": "shell", + "command": "npm", + "args": ["run", "build"], + "options": { + "cwd": "${workspaceFolder}/apps/wallet-server" + }, + "problemMatcher": ["$tsc"] + }, + { + "label": "dev:wallet", + "type": "shell", + "command": "npm", + "args": ["run", "dev"], + "options": { + "cwd": "${workspaceFolder}/apps/wallet-server" + }, + "isBackground": true, + "problemMatcher": [] } ] } diff --git a/WALLET_MCP_PLAN.md b/WALLET_MCP_PLAN.md index e87deea..2b1499f 100644 --- a/WALLET_MCP_PLAN.md +++ b/WALLET_MCP_PLAN.md @@ -601,3 +601,7 @@ Proceeding with fast, iterative implementation in this order: 4. Phase 3.6: Credential client (4-5 hours) 5. Phase 3.7: Message client (3-4 hours) 6. Testing & iteration + + +TODO: +* Persistent wallet storage - currently only in memory so is wiped whenever you restart the server \ No newline at end of file diff --git a/apps/truvera-api/Dockerfile b/apps/truvera-api/Dockerfile index 83909f9..1bdbfb4 100644 --- a/apps/truvera-api/Dockerfile +++ b/apps/truvera-api/Dockerfile @@ -13,6 +13,7 @@ RUN apk update && apk upgrade --no-cache && \ # Copy root package files for workspace COPY package*.json ./ +COPY scripts ./scripts # Copy workspace package.json files first (for Docker layer caching) COPY packages/mcp-shared/package*.json ./packages/mcp-shared/ @@ -46,6 +47,7 @@ RUN apk update && apk upgrade --no-cache && \ # Copy root package files COPY package*.json ./ +COPY scripts ./scripts # Include repository license in the published runtime image COPY LICENSE /licenses/LICENSE diff --git a/apps/truvera-api/src/build-info.ts b/apps/truvera-api/src/build-info.ts index 72653a0..b21b7bd 100644 --- a/apps/truvera-api/src/build-info.ts +++ b/apps/truvera-api/src/build-info.ts @@ -1,6 +1,6 @@ // Auto-generated build information export const BUILD_INFO = { - timestamp: '2026-04-02T20:53:22.032Z', - buildNumber: 40, - version: '1.0.0-build.40', + timestamp: '2026-04-15T19:47:05.026Z', + buildNumber: 46, + version: '1.0.0-build.46', }; diff --git a/apps/wallet-server/.env.test b/apps/wallet-server/.env.test new file mode 100644 index 0000000..2a6271e --- /dev/null +++ b/apps/wallet-server/.env.test @@ -0,0 +1,9 @@ +# Truvera API Configuration +TRUVERA_API_KEY=eyJzY29wZXMiOlsidGVzdCIsImFsbCJdLCJzdWIiOiIyMTYyNiIsInNlbGVjdGVkVGVhbUlkIjowLCJjcmVhdG9ySWQiOiIyMyIsImZtdCI6MSwiaWF0IjoxNzczNzcwNDU2LCJleHAiOjQ4NTMwNjY0NTZ9.K9TIa50Saw4SC63PGPWVWQw21dxq06awpL6vhhqs2igmWOxiWexNxF3f8hRmebEAchEhUKeBpq07dbU2fHEZAw +TRUVERA_API_ENDPOINT=https://api-testnet.truvera.io + +# Node environment +NODE_ENV=development +TRUVERA_API_ISSUER_DID=did:cheqd:testnet:74e21607-cb71-4751-a79e-1b9a2a8aa986 + +TRUVERA_RUN_LIVE_TESTS=true diff --git a/apps/wallet-server/Dockerfile b/apps/wallet-server/Dockerfile new file mode 100644 index 0000000..24f9023 --- /dev/null +++ b/apps/wallet-server/Dockerfile @@ -0,0 +1,69 @@ +# Multi-stage build for Wallet MCP Service +ARG BUILD_NUMBER=1 + +FROM node:22-alpine3.23 AS builder + +ARG BUILD_NUMBER + +WORKDIR /app + +RUN apk update && apk upgrade --no-cache && \ + apk add --no-cache openssl + +RUN npm install -g patch-package@8.0.1 + +COPY package*.json ./ +COPY scripts ./scripts +COPY packages/mcp-shared/package*.json ./packages/mcp-shared/ +COPY apps/wallet-server/package*.json ./apps/wallet-server/ +COPY apps/wallet-server/patches ./apps/wallet-server/patches + +RUN npm ci --workspaces + +COPY packages/mcp-shared ./packages/mcp-shared +RUN npm run build --workspace=packages/mcp-shared + +COPY apps/wallet-server/src ./apps/wallet-server/src +COPY apps/wallet-server/scripts ./apps/wallet-server/scripts +COPY apps/wallet-server/register-aliases.cjs ./apps/wallet-server/ +COPY apps/wallet-server/tsconfig.json ./apps/wallet-server/ + +RUN BUILD_NUMBER=$BUILD_NUMBER npm run build --workspace=apps/wallet-server + +FROM node:22-alpine3.23 + +WORKDIR /app + +RUN apk update && apk upgrade --no-cache && \ + apk add --no-cache openssl + +RUN npm install -g patch-package@8.0.1 + +COPY package*.json ./ +COPY scripts ./scripts +COPY LICENSE /licenses/LICENSE +COPY packages/mcp-shared/package*.json ./packages/mcp-shared/ +COPY apps/wallet-server/package*.json ./apps/wallet-server/ +COPY apps/wallet-server/patches ./apps/wallet-server/patches + +RUN npm ci --workspaces --omit=dev + +RUN rm -rf /usr/local/lib/node_modules/npm \ + && rm -f /usr/local/bin/npm /usr/local/bin/npx + +COPY --from=builder /app/packages/mcp-shared/dist ./packages/mcp-shared/dist +COPY --from=builder /app/packages/mcp-shared/package.json ./packages/mcp-shared/ +COPY --from=builder /app/apps/wallet-server/dist ./apps/wallet-server/dist +COPY --from=builder /app/apps/wallet-server/register-aliases.cjs ./apps/wallet-server/register-aliases.cjs + +RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 +USER nodejs + +WORKDIR /app/apps/wallet-server + +EXPOSE 3001 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD node -e "fetch('http://127.0.0.1:3001/health').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))" + +CMD ["node", "-r", "./register-aliases.cjs", "dist/index.js"] \ No newline at end of file diff --git a/apps/wallet-server/README.md b/apps/wallet-server/README.md index 9170a14..aaedd96 100644 --- a/apps/wallet-server/README.md +++ b/apps/wallet-server/README.md @@ -20,14 +20,13 @@ A Model Context Protocol (MCP) server for interacting with the Truvera Wallet SD | Credential management | ⏳ Planned | | DIDComm messaging | ⏳ Planned | | Tests | ⏳ Minimal | -| Docker support | ⏳ Not yet | +| Docker support | ✅ Included | | Production hardening | ⏳ Not yet | ### Known limitations - **In-memory storage only:** The current wallet-server wiring uses in-memory local storage adapters. This is suitable for development and tests, but persistence and cloud sync hardening are still pending. -- **No Docker image:** There is no Dockerfile yet. The server can only be run locally via Node.js. -- **No CI coverage:** The wallet-server is not yet included in automated CI tests. +- **Local-only wallet state:** Containerized runs are useful for MCP integration testing, but the wallet still uses in-memory backing stores today. --- @@ -54,6 +53,12 @@ cp .env.example .env npm run build ``` +From the repo root you can also use: + +```bash +npm run build:wallet +``` + ### 4. Run ```bash @@ -67,6 +72,38 @@ MCP_MODE=stdio npm start npm run dev ``` +From the repo root: + +```bash +npm run dev:wallet +``` + +### 5. Docker workflow + +From the repo root: + +```bash +# Build the image +npm run docker:build:wallet + +# Start the container in HTTP mode on port 3001 +npm run docker:run:wallet +``` + +Or from this directory: + +```bash +docker-compose up -d +``` + +### 6. Verify the server is running + +```bash +curl http://localhost:3001/health +``` + +If port 3001 is already in use and you start the server from an interactive terminal, the server now prompts to continue on the next available port instead of exiting immediately. + ### MCP Inspector (shared docs) Use the shared MCP Inspector instructions in the repo root README: @@ -81,13 +118,26 @@ Use the shared MCP Inspector instructions in the repo root README: |----------|----------|---------|-------------| | `WALLET_MASTER_KEY` | Yes | — | Master encryption key for the wallet | | `MCP_MODE` | No | `stdio` | Transport: `http` or `stdio` | -| `MCP_PORT` | No | `3010` | HTTP port (only used when `MCP_MODE=http`) | +| `MCP_PORT` | No | `3001` | HTTP port (only used when `MCP_MODE=http`) | | `CHEQD_NETWORK` | No | `testnet` | Cheqd network: `testnet` or `mainnet` | | `EDV_STORAGE_URL` | No | `https://edv.dock.io` | EDV cloud storage endpoint | | `WALLET_NAME` | No | `mcp-wallet` | Wallet label | --- +## Running tests + +```bash +# Unit tests +npm test + +# Integration tests +npm run test:integration + +# Type checking only +npm run typecheck +``` + ## Planned architecture See [WALLET_MCP_PLAN.md](../../WALLET_MCP_PLAN.md) at the repo root for the full development plan. diff --git a/apps/wallet-server/docker-compose.yml b/apps/wallet-server/docker-compose.yml new file mode 100644 index 0000000..ab6bb16 --- /dev/null +++ b/apps/wallet-server/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3.8' + +services: + wallet-mcp-service: + build: + context: ../.. + dockerfile: apps/wallet-server/Dockerfile + container_name: wallet-mcp-service + environment: + - WALLET_MASTER_KEY=${WALLET_MASTER_KEY} + - MCP_MODE=${MCP_MODE:-http} + - MCP_PORT=3001 + - CHEQD_NETWORK=${CHEQD_NETWORK:-testnet} + - WALLET_NAME=${WALLET_NAME:-mcp-wallet} + - NODE_ENV=production + ports: + - "3001:3001" + restart: unless-stopped + networks: + - mcp-network + +networks: + mcp-network: + driver: bridge \ No newline at end of file diff --git a/apps/wallet-server/eslint.config.js b/apps/wallet-server/eslint.config.js new file mode 100644 index 0000000..1c2ef23 --- /dev/null +++ b/apps/wallet-server/eslint.config.js @@ -0,0 +1,50 @@ +import tseslint from '@typescript-eslint/eslint-plugin'; +import tsparser from '@typescript-eslint/parser'; + +export default [ + { + files: ['src/**/*.ts'], + languageOptions: { + parser: tsparser, + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, + globals: { + console: 'readonly', + process: 'readonly', + __dirname: 'readonly', + __filename: 'readonly', + Buffer: 'readonly', + NodeJS: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tseslint, + }, + rules: { + ...tseslint.configs.recommended.rules, + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'warn', + 'no-console': 'off', + }, + }, + { + ignores: [ + 'dist/**', + 'node_modules/**', + '**/*.js', + 'coverage/**', + '.vscode/**', + ], + }, +]; \ No newline at end of file diff --git a/apps/wallet-server/jest.integration.config.cjs b/apps/wallet-server/jest.integration.config.cjs index cc85fdc..1a34223 100644 --- a/apps/wallet-server/jest.integration.config.cjs +++ b/apps/wallet-server/jest.integration.config.cjs @@ -22,6 +22,8 @@ module.exports = { ], }, moduleNameMapper: { + // Resolve TypeScript ESM-style .js extension imports to their source .ts files + "^(\\.{1,2}/.*)\\.js$": "$1", "^ky-universal$": "ky", "^base58-universal$": "/../../node_modules/base58-universal/main.js", "^base64url-universal$": "/../../node_modules/base64url-universal/lib/index.js", diff --git a/apps/wallet-server/jest.setup.js b/apps/wallet-server/jest.setup.js index 6d9f0f4..fab928a 100644 --- a/apps/wallet-server/jest.setup.js +++ b/apps/wallet-server/jest.setup.js @@ -7,3 +7,15 @@ jest.mock('@docknetwork/wallet-sdk-wasm/src/services/blockchain', () => ({ isBlockchainReady: true, }, })); + +// The wallet SDK can emit late debug logs from background status updates. +// Keep integration tests deterministic by silencing data-store logger output. +jest.mock('@docknetwork/wallet-sdk-data-store/src/logger', () => ({ + logger: { + debug: jest.fn(), + performance: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + }, +})); diff --git a/apps/wallet-server/package.json b/apps/wallet-server/package.json index 336d6ac..bb02ce8 100644 --- a/apps/wallet-server/package.json +++ b/apps/wallet-server/package.json @@ -5,13 +5,18 @@ "type": "module", "main": "dist/index.js", "scripts": { + "prebuild": "node scripts/update-build-version.js", "build": "tsc", - "start": "node dist/index.js", + "start": "node -r ./register-aliases.cjs dist/index.js", "dev": "tsx src/index.ts", "typecheck": "tsc --noEmit", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", "test": "vitest run src/features/credentials/tests/unit/credentials-tools.test.ts src/features/dids/tests/unit/dids-tools.test.ts", "test:watch": "vitest src/features/credentials/tests/unit/credentials-tools.test.ts src/features/dids/tests/unit/dids-tools.test.ts", - "test:integration": "jest --config jest.integration.config.cjs --runInBand" + "test:integration": "jest --config jest.integration.config.cjs --runInBand", + "docker:build": "cd ../.. && docker build --build-arg BUILD_NUMBER=\"$(cat apps/wallet-server/.buildnumber)\" -t truvera-wallet-mcp:latest -t truvera-wallet-mcp:$(cat apps/wallet-server/.buildnumber) -f apps/wallet-server/Dockerfile .", + "docker:run": "docker rm -f truvera-wallet-mcp || true && docker run -d --name truvera-wallet-mcp --env-file ./.env -e MCP_MODE=http -e MCP_PORT=3001 -p 3001:3001 truvera-wallet-mcp:latest" }, "dependencies": { "@truvera/mcp-shared": "file:../../packages/mcp-shared", @@ -19,14 +24,18 @@ "@docknetwork/wallet-sdk-core": "^1.7.0", "@docknetwork/wallet-sdk-data-store": "^1.7.0", "@docknetwork/wallet-sdk-data-store-web": "^1.7.0", - "dotenv": "^16.6.1" + "dotenv": "^16.6.1", + "module-alias": "^2.2.3" }, "devDependencies": { "@babel/core": "^7.26.0", "@babel/preset-env": "^7.26.0", "@types/jest": "^29.5.14", "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", "babel-jest": "^29.7.0", + "eslint": "^10.0.2", "jest": "^29.7.0", "ts-jest": "^29.2.5", "tsx": "^4.7.0", diff --git a/apps/wallet-server/patches/@digitalbazaar+did-io+1.1.0.patch b/apps/wallet-server/patches/@digitalbazaar+did-io+1.1.0.patch new file mode 100644 index 0000000..74f5ed2 --- /dev/null +++ b/apps/wallet-server/patches/@digitalbazaar+did-io+1.1.0.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@digitalbazaar/did-io/lib/CachedResolver.js b/node_modules/@digitalbazaar/did-io/lib/CachedResolver.js +index bfd0673..e830d09 100644 +--- a/node_modules/@digitalbazaar/did-io/lib/CachedResolver.js ++++ b/node_modules/@digitalbazaar/did-io/lib/CachedResolver.js +@@ -2,7 +2,7 @@ + * Copyright (c) 2021 Digital Bazaar, Inc. All rights reserved. + */ + import {parseDid} from './did-io.js'; +-import {LruCache} from '@digitalbazaar/lru-memoize'; ++import {LruCache} from '@digitalbazaar/lru-memoize/lib/main.js'; + + export class CachedResolver { + /** diff --git a/apps/wallet-server/patches/@digitalbazaar+did-method-key+2.0.0.patch b/apps/wallet-server/patches/@digitalbazaar+did-method-key+2.0.0.patch new file mode 100644 index 0000000..c1d3025 --- /dev/null +++ b/apps/wallet-server/patches/@digitalbazaar+did-method-key+2.0.0.patch @@ -0,0 +1,24 @@ +diff --git a/node_modules/@digitalbazaar/did-method-key/lib/DidKeyDriver.js b/node_modules/@digitalbazaar/did-method-key/lib/DidKeyDriver.js +index 7e25886..d879c5a 100644 +--- a/node_modules/@digitalbazaar/did-method-key/lib/DidKeyDriver.js ++++ b/node_modules/@digitalbazaar/did-method-key/lib/DidKeyDriver.js +@@ -3,15 +3,15 @@ + */ + import { + Ed25519VerificationKey2020 +-} from '@digitalbazaar/ed25519-verification-key-2020'; ++} from '@digitalbazaar/ed25519-verification-key-2020/lib/main.js'; + import { + X25519KeyAgreementKey2020 +-} from '@digitalbazaar/x25519-key-agreement-key-2020'; ++} from '@digitalbazaar/x25519-key-agreement-key-2020/lib/main.js'; + import { + X25519KeyAgreementKey2019 +-} from '@digitalbazaar/x25519-key-agreement-key-2019'; ++} from '@digitalbazaar/x25519-key-agreement-key-2019/lib/main.js'; + +-import * as didIo from '@digitalbazaar/did-io'; ++import * as didIo from '@digitalbazaar/did-io/lib/main.js'; + + const DID_CONTEXT_URL = 'https://www.w3.org/ns/did/v1'; + // For backwards compat only, not actually importing this suite diff --git a/apps/wallet-server/patches/@digitalbazaar+minimal-cipher+4.0.2.patch b/apps/wallet-server/patches/@digitalbazaar+minimal-cipher+4.0.2.patch new file mode 100644 index 0000000..6d7f3f6 --- /dev/null +++ b/apps/wallet-server/patches/@digitalbazaar+minimal-cipher+4.0.2.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@digitalbazaar/minimal-cipher/util.js b/node_modules/@digitalbazaar/minimal-cipher/util.js +index 50a6441..71212d8 100644 +--- a/node_modules/@digitalbazaar/minimal-cipher/util.js ++++ b/node_modules/@digitalbazaar/minimal-cipher/util.js +@@ -2,7 +2,7 @@ + import {TextDecoder, TextEncoder} from 'util'; + export {TextDecoder, TextEncoder}; + +-export {ReadableStream, TransformStream} from 'web-streams-polyfill/ponyfill'; ++export {ReadableStream, TransformStream} from 'web-streams-polyfill/dist/ponyfill.js'; + + export function stringToUint8Array(data) { + if(typeof data === 'string') { diff --git a/apps/wallet-server/patches/base58-universal+1.0.0.patch b/apps/wallet-server/patches/base58-universal+1.0.0.patch new file mode 100644 index 0000000..9708bee --- /dev/null +++ b/apps/wallet-server/patches/base58-universal+1.0.0.patch @@ -0,0 +1,126 @@ +diff --git a/node_modules/base58-universal/index.js b/node_modules/base58-universal/index.js +index c1ff223..8f49bcc 100644 +--- a/node_modules/base58-universal/index.js ++++ b/node_modules/base58-universal/index.js +@@ -3,6 +3,118 @@ + */ + 'use strict'; + +-// translate `main.js` to CommonJS +-require = require('esm')(module); +-module.exports = require('./main.js'); ++// Node 24 compatibility: avoid the legacy `esm` runtime shim. ++// This file provides a CommonJS implementation equivalent to `main.js`. ++const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; ++const reverseAlphabets = Object.create(null); ++ ++function encodeBaseN(input, alphabetValue, maxline) { ++ if(!(input instanceof Uint8Array)) { ++ throw new TypeError('"input" must be a Uint8Array.'); ++ } ++ if(typeof alphabetValue !== 'string') { ++ throw new TypeError('"alphabet" must be a string.'); ++ } ++ if(maxline !== undefined && typeof maxline !== 'number') { ++ throw new TypeError('"maxline" must be a number.'); ++ } ++ if(input.length === 0) { ++ return ''; ++ } ++ ++ let output = ''; ++ const base = alphabetValue.length; ++ const first = alphabetValue.charAt(0); ++ const digits = [0]; ++ ++ for(let i = 0; i < input.length; ++i) { ++ let carry = input[i]; ++ for(let j = 0; j < digits.length; ++j) { ++ carry += digits[j] << 8; ++ digits[j] = carry % base; ++ carry = (carry / base) | 0; ++ } ++ ++ while(carry > 0) { ++ digits.push(carry % base); ++ carry = (carry / base) | 0; ++ } ++ } ++ ++ for(let i = 0; input[i] === 0 && i < input.length - 1; ++i) { ++ output += first; ++ } ++ for(let i = digits.length - 1; i >= 0; --i) { ++ output += alphabetValue[digits[i]]; ++ } ++ ++ if(maxline) { ++ const regex = new RegExp('.{1,' + maxline + '}', 'g'); ++ output = output.match(regex).join('\r\n'); ++ } ++ ++ return output; ++} ++ ++function decodeBaseN(input, alphabetValue) { ++ if(typeof input !== 'string') { ++ throw new TypeError('"input" must be a string.'); ++ } ++ if(typeof alphabetValue !== 'string') { ++ throw new TypeError('"alphabet" must be a string.'); ++ } ++ if(input.length === 0) { ++ return new Uint8Array(); ++ } ++ ++ let table = reverseAlphabets[alphabetValue]; ++ if(!table) { ++ table = reverseAlphabets[alphabetValue] = []; ++ for(let i = 0; i < alphabetValue.length; ++i) { ++ table[alphabetValue.charCodeAt(i)] = i; ++ } ++ } ++ ++ input = input.replace(/\s/g, ''); ++ ++ const base = alphabetValue.length; ++ const first = alphabetValue.charAt(0); ++ const bytes = [0]; ++ for(let i = 0; i < input.length; i++) { ++ const value = table[input.charCodeAt(i)]; ++ if(value === undefined) { ++ return; ++ } ++ ++ let carry = value; ++ for(let j = 0; j < bytes.length; ++j) { ++ carry += bytes[j] * base; ++ bytes[j] = carry & 0xff; ++ carry >>= 8; ++ } ++ ++ while(carry > 0) { ++ bytes.push(carry & 0xff); ++ carry >>= 8; ++ } ++ } ++ ++ for(let k = 0; input[k] === first && k < input.length - 1; ++k) { ++ bytes.push(0); ++ } ++ ++ return new Uint8Array(bytes.reverse()); ++} ++ ++function encode(input, maxline) { ++ return encodeBaseN(input, alphabet, maxline); ++} ++ ++function decode(input) { ++ return decodeBaseN(input, alphabet); ++} ++ ++module.exports = { ++ encode, ++ decode, ++}; diff --git a/apps/wallet-server/register-aliases.cjs b/apps/wallet-server/register-aliases.cjs new file mode 100644 index 0000000..07a86d2 --- /dev/null +++ b/apps/wallet-server/register-aliases.cjs @@ -0,0 +1,16 @@ +const path = require("path"); +const moduleAlias = require("module-alias"); + +const rootNodeModules = path.resolve(__dirname, "../../node_modules"); + +moduleAlias.addAliases({ + "@digitalbazaar/did-method-key": path.join(rootNodeModules, "@digitalbazaar/did-method-key/lib/main.js"), + "@digitalbazaar/did-io": path.join(rootNodeModules, "@digitalbazaar/did-io/lib/main.js"), + "@digitalbazaar/minimal-cipher": path.join(rootNodeModules, "@digitalbazaar/minimal-cipher/Cipher.js"), + "@digitalbazaar/x25519-key-agreement-key-2020": path.join(rootNodeModules, "@digitalbazaar/x25519-key-agreement-key-2020/lib/main.js"), + "@digitalbazaar/x25519-key-agreement-key-2019": path.join(rootNodeModules, "@digitalbazaar/x25519-key-agreement-key-2019/lib/main.js"), + "@digitalbazaar/ed25519-verification-key-2020": path.join(rootNodeModules, "@digitalbazaar/ed25519-verification-key-2020/lib/main.js"), + "@digitalbazaar/ed25519-verification-key-2018": path.join(rootNodeModules, "@digitalbazaar/ed25519-verification-key-2018/src/main.js"), + // Force modern CJS build to avoid legacy `esm` wrapper crashes on Node 24. + "@digitalbazaar/http-client": path.join(rootNodeModules, "jsonld/node_modules/@digitalbazaar/http-client/dist/cjs/index.cjs"), +}); diff --git a/apps/wallet-server/scripts/update-build-version.js b/apps/wallet-server/scripts/update-build-version.js new file mode 100644 index 0000000..f9d6c8d --- /dev/null +++ b/apps/wallet-server/scripts/update-build-version.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const buildInfoPath = path.join(__dirname, '../src/build-info.ts'); +const buildNumberPath = path.join(__dirname, '../.buildnumber'); + +let buildNumber = process.env.BUILD_NUMBER ? parseInt(process.env.BUILD_NUMBER, 10) : null; + +if (!buildNumber || isNaN(buildNumber)) { + if (fs.existsSync(buildNumberPath)) { + const content = fs.readFileSync(buildNumberPath, 'utf-8').trim(); + buildNumber = parseInt(content, 10) || 1; + buildNumber++; + } else { + buildNumber = 1; + } + + fs.writeFileSync(buildNumberPath, String(buildNumber), 'utf-8'); +} + +const timestamp = new Date().toISOString(); +const packageVersion = process.env.npm_package_version || '0.1.0'; +const fullVersion = `${packageVersion}-build.${buildNumber}`; + +const buildInfo = `// Auto-generated build information +export const BUILD_INFO = { + timestamp: '${timestamp}', + buildNumber: ${buildNumber}, + version: '${fullVersion}', +}; +`; + +fs.writeFileSync(buildInfoPath, buildInfo, 'utf-8'); +console.log(`✓ Updated build info: Version ${fullVersion} (${timestamp})`); \ No newline at end of file diff --git a/apps/wallet-server/src/build-info.ts b/apps/wallet-server/src/build-info.ts index cbf4561..67a3a39 100644 --- a/apps/wallet-server/src/build-info.ts +++ b/apps/wallet-server/src/build-info.ts @@ -1,7 +1,6 @@ -import type { BuildInfo } from "@truvera/mcp-shared/types"; - -export const BUILD_INFO: BuildInfo = { - version: "0.1.0", - buildNumber: 1, - timestamp: new Date().toISOString(), +// Auto-generated build information +export const BUILD_INFO = { + timestamp: '2026-04-15T19:47:06.099Z', + buildNumber: 14, + version: '0.1.0-build.14', }; diff --git a/apps/wallet-server/src/features/credentials/client.ts b/apps/wallet-server/src/features/credentials/client.ts index 6fa1770..6851563 100644 --- a/apps/wallet-server/src/features/credentials/client.ts +++ b/apps/wallet-server/src/features/credentials/client.ts @@ -3,9 +3,7 @@ * Manages credential operations using the Dock Wallet SDK */ -import { createCredentialProvider } from "@docknetwork/wallet-sdk-core/lib/credential-provider"; -import { createDIDProvider } from "@docknetwork/wallet-sdk-core/lib/did-provider"; -import type { IWallet, ICredentialProvider, IDIDProvider } from "@docknetwork/wallet-sdk-core/lib/types"; +import type { IWallet, ICredentialProvider, IDIDProvider } from "@docknetwork/wallet-sdk-core/lib/types.js"; import type { CredentialListResult, CredentialInfo, ImportCredentialResult } from "./types.js"; export class CredentialClient { @@ -21,8 +19,9 @@ export class CredentialClient { /** * Initialize the credential provider */ - private ensureProvider(): ICredentialProvider { + private async ensureProvider(): Promise { if (!this.credentialProvider) { + const { createCredentialProvider } = await import("@docknetwork/wallet-sdk-core/lib/credential-provider.js"); this.credentialProvider = createCredentialProvider({ wallet: this.wallet }); } return this.credentialProvider; @@ -31,8 +30,9 @@ export class CredentialClient { /** * Initialize the DID provider (required for credential import) */ - private ensureDIDProvider(): IDIDProvider { + private async ensureDIDProvider(): Promise { if (!this.didProvider) { + const { createDIDProvider } = await import("@docknetwork/wallet-sdk-core/lib/did-provider.js"); this.didProvider = createDIDProvider({ wallet: this.wallet }); } return this.didProvider; @@ -43,8 +43,8 @@ export class CredentialClient { */ async importCredential(uri: string): Promise { try { - const credentialProvider = this.ensureProvider(); - const didProvider = this.ensureDIDProvider(); + const credentialProvider = await this.ensureProvider(); + const didProvider = await this.ensureDIDProvider(); const before = await credentialProvider.getCredentials(); const beforeIds = new Set(before.map((doc: any) => doc?.id).filter(Boolean)); @@ -96,7 +96,7 @@ export class CredentialClient { * List all credentials in the wallet */ async listCredentials(): Promise { - const provider = this.ensureProvider(); + const provider = await this.ensureProvider(); const allDocs = await provider.getCredentials(); // Map credentials to our standardized format diff --git a/apps/wallet-server/src/features/credentials/tests/integration/credential-proof-response.e2e.test.ts b/apps/wallet-server/src/features/credentials/tests/integration/credential-proof-response.e2e.test.ts new file mode 100644 index 0000000..0793a05 --- /dev/null +++ b/apps/wallet-server/src/features/credentials/tests/integration/credential-proof-response.e2e.test.ts @@ -0,0 +1,183 @@ +/** + * Live end-to-end test for the proof request response flow, exercised through + * the MCP tool handler layer. + * + * Flow: + * 1) Create a DID via the `create_did` tool handler + * 2) Import a credential via the `import_credential` tool handler + * 3) Create a proof request from the predefined template via Truvera API (direct HTTP) + * 4) Respond to the proof request via the `respond_to_proof_request` tool handler + * → builds and returns a verifiable presentation + * 5) Verify the presentation via Truvera /verify (direct HTTP) + * → the presentation must pass verification + * + * Requirements: + * TRUVERA_RUN_LIVE_TESTS=true + * TRUVERA_API_KEY= + * + * Run via: npm run test:integration + */ + +import { describe, it, expect, beforeAll, afterAll } from "@jest/globals"; + +import { WalletClient } from "../../../../wallet-client"; +import { DIDClient } from "../../../dids/client"; +import { CredentialClient } from "../../client"; +import { getDIDHandlers } from "../../../dids/tools"; +import { getCredentialHandlers } from "../../tools"; +import { requireLiveTestEnv, TRUVERA_API_ENDPOINT, liveApiKey } from "../../../../tests/helpers/live-test-gate"; + +// ── Constants ──────────────────────────────────────────────────────────────── + +const OID4VCI_TEST_OFFER_URI = + "openid-credential-offer://?credential_offer_uri=https://api-testnet.truvera.io/openid/credential-offers/f3a5398e-e991-4ff8-9e45-7c29873cc39b"; +const PROOF_TEMPLATE_ID = "caa741b3-aa21-4bbc-b51d-e82148a7e435"; + +// ── Helpers ─────────────────────────────────────────────────────────────────── + +/** Parse the text content from an MCP tool handler response. */ +function parseToolResult(result: unknown): unknown { + const r = result as any; + const text = r?.content?.[0]?.text; + if (typeof text !== "string") { + throw new Error(`Unexpected tool result shape: ${JSON.stringify(result)}`); + } + return JSON.parse(text); +} + +/** + * Call the Truvera API to create a fresh proof request from the given template. + * Returns the full proof request object (the document the wallet SDK needs to + * feed into the verification controller). + */ +async function createProofRequestFromTemplate(templateId: string): Promise> { + const response = await fetch( + `${TRUVERA_API_ENDPOINT}/proof-templates/${encodeURIComponent(templateId)}/request`, + { + method: "POST", + headers: { + Authorization: `Bearer ${liveApiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ name: `wallet-proof-response-e2e-${Date.now()}` }), + } + ); + + const raw = await response.text(); + if (!response.ok) { + throw new Error(`Failed to create proof request (${response.status}): ${raw}`); + } + + const parsed: any = JSON.parse(raw); + // The API may return the proof-request object directly, or nested under a key. + const candidates: unknown[] = [parsed, parsed?.data, parsed?.proofRequest, parsed?.request]; + const proofRequest = candidates.find( + (c) => c && typeof c === "object" && typeof (c as any).request === "object" + ) as Record | undefined; + + if (!proofRequest) { + throw new Error(`Proof request object not found in API response: ${raw}`); + } + + return proofRequest; +} + +/** + * Verify a presentation via Truvera /verify. + * Tries the plain presentation first, then common wrapper shapes. + */ +async function verifyPresentation(presentation: unknown): Promise<{ verified: boolean }> { + const payloads = [presentation, { data: presentation }]; + let lastBody = ""; + + for (const payload of payloads) { + const response = await fetch(`${TRUVERA_API_ENDPOINT}/verify`, { + method: "POST", + headers: { + Authorization: `Bearer ${liveApiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + }); + + const raw = await response.text(); + lastBody = raw; + + if (!response.ok) continue; + + const parsed: any = JSON.parse(raw); + const candidates: unknown[] = [parsed, parsed?.data, parsed?.result, parsed?.data?.result]; + for (const c of candidates) { + if (c && typeof c === "object" && typeof (c as any).verified === "boolean") { + return { verified: (c as any).verified }; + } + } + } + + throw new Error(`Unable to determine verified status from /verify response. Last body: ${lastBody}`); +} + +// ── Test suite ──────────────────────────────────────────────────────────────── + +describe("e2e: credential import → proof request response (via MCP tool handlers)", () => { + let walletClient: WalletClient; + let handlers: Map Promise>; + + beforeAll(async () => { + requireLiveTestEnv(); + + const uniqueWalletName = `proof-e2e-wallet-${Date.now()}-${Math.random()}`; + walletClient = new WalletClient(uniqueWalletName, "testnet"); + + const wallet = await walletClient.initialize(); + const didClient = new DIDClient(wallet); + const credentialClient = new CredentialClient(wallet); + + handlers = new Map([ + ...getDIDHandlers(didClient), + ...getCredentialHandlers(credentialClient), + ]) as Map Promise>; + }); + + afterAll(async () => { + if (walletClient) { + await walletClient.waitForIdle(); + } + if (walletClient?.isInitialized()) { + try { + await walletClient.deleteWallet(); + await walletClient.waitForIdle(); + } catch (error) { + console.error("Error cleaning up wallet:", error); + } + } + }); + + it("creates a DID, imports a credential, responds to a proof request, and the presentation verifies", async () => { + // ── Step 1: create a DID ───────────────────────────────────────────────── + const createDIDResult = parseToolResult(await handlers.get("create_did")!({})) as any; + expect(createDIDResult.success).toBe(true); + expect(createDIDResult.did).toMatch(/^did:/); + + // ── Step 2: import credential ──────────────────────────────────────────── + const importResult = parseToolResult( + await handlers.get("import_credential")!({ uri: OID4VCI_TEST_OFFER_URI }) + ) as any; + expect(importResult.success).toBe(true); + + // ── Step 3: create proof request via Truvera API ───────────────────────── + const proofRequest = await createProofRequestFromTemplate(PROOF_TEMPLATE_ID); + expect(proofRequest).toBeDefined(); + + // ── Step 4: respond to proof request via MCP tool (not yet implemented) ── + const presentationResult = parseToolResult( + await handlers.get("respond_to_proof_request")!({ proofRequest }) + ) as any; + expect(presentationResult.success).toBe(true); + expect(presentationResult.presentation).toBeDefined(); + + // ── Step 5: verify the presentation ───────────────────────────────────── + const verification = await verifyPresentation(presentationResult.presentation); + expect(verification.verified).toBe(true); + }); +}); diff --git a/apps/wallet-server/src/features/credentials/tests/integration/credentials-client.test.ts b/apps/wallet-server/src/features/credentials/tests/integration/credentials-client.test.ts index ba67d14..f87957f 100644 --- a/apps/wallet-server/src/features/credentials/tests/integration/credentials-client.test.ts +++ b/apps/wallet-server/src/features/credentials/tests/integration/credentials-client.test.ts @@ -7,10 +7,15 @@ import { describe, it, expect, beforeEach, afterEach } from "@jest/globals"; import { WalletClient } from "../../../../wallet-client"; import { CredentialClient } from "../../client"; +import { DIDClient } from "../../../dids/client"; + +const OID4VCI_TEST_OFFER_URI = + "openid-credential-offer://?credential_offer_uri=https://api-testnet.truvera.io/openid/credential-offers/fbe0a6ed-2aa8-4363-833b-6aa8fe1c6d01"; describe("integration: CredentialClient with real Wallet SDK", () => { let walletClient: WalletClient; let credentialClient: CredentialClient; + let didClient: DIDClient; beforeEach(async () => { // Create a unique wallet for each test to avoid conflicts @@ -20,19 +25,23 @@ describe("integration: CredentialClient with real Wallet SDK", () => { // Initialize wallet and credential client const wallet = await walletClient.initialize(); credentialClient = new CredentialClient(wallet); + didClient = new DIDClient(wallet); }); afterEach(async () => { + if (walletClient) { + await walletClient.waitForIdle(); + } + // Clean up wallet resources after each test if (walletClient && walletClient.isInitialized()) { try { await walletClient.deleteWallet(); + await walletClient.waitForIdle(); } catch (error) { console.error("Error cleaning up wallet:", error); } } - // Wait for remaining async operations to complete - await new Promise((resolve) => setTimeout(resolve, 100)); }); describe("listCredentials", () => { @@ -85,4 +94,82 @@ describe("integration: CredentialClient with real Wallet SDK", () => { expect(result.count).toBeGreaterThanOrEqual(0); }); }); + + describe("importCredential", () => { + it("returns success: false with a message when URI is malformed", async () => { + const result = await credentialClient.importCredential("not-a-valid-uri"); + + expect(result.success).toBe(false); + expect(typeof result.message).toBe("string"); + expect(result.message!.length).toBeGreaterThan(0); + expect(result.credential).toBeUndefined(); + }); + + it("returns success: false when the credential offer URI is unreachable", async () => { + const result = await credentialClient.importCredential( + "openid-credential-offer://?credential_offer_uri=https://localhost:19999/offer/does-not-exist" + ); + + expect(result.success).toBe(false); + expect(typeof result.message).toBe("string"); + expect(result.message!.length).toBeGreaterThan(0); + }); + + it("does not alter the credential list after a failed import", async () => { + const before = await credentialClient.listCredentials(); + + await credentialClient.importCredential("not-a-valid-uri"); + + const after = await credentialClient.listCredentials(); + expect(after.count).toBe(before.count); + }); + + it("initialises the DID provider lazily alongside the credential provider", async () => { + // Calling importCredential bootstraps both providers internally. + // A second call should reuse them without error. + const first = await credentialClient.importCredential("not-a-valid-uri"); + const second = await credentialClient.importCredential("not-a-valid-uri"); + + expect(first.success).toBe(false); + expect(second.success).toBe(false); + }); + + it("result always conforms to ImportCredentialResult shape", async () => { + const result = await credentialClient.importCredential("bad-uri"); + + expect(result).toHaveProperty("success"); + expect(typeof result.success).toBe("boolean"); + // message is present on failure + expect(result).toHaveProperty("message"); + }); + + it("imports credential from OID4VCI offer URL and stores it in the wallet SDK", async () => { + // Ensure the wallet has a DID available before import. + await didClient.createDID(); + + const before = await credentialClient.listCredentials(); + + const importResult = await credentialClient.importCredential(OID4VCI_TEST_OFFER_URI); + expect(importResult.success).toBe(true); + expect(importResult.credential).toBeDefined(); + + const after = await credentialClient.listCredentials(); + expect(after.count).toBeGreaterThan(before.count); + + // Verify the imported credential is visible via wallet-sdk provider storage too. + const { createCredentialProvider } = await import("@docknetwork/wallet-sdk-core/lib/credential-provider.js"); + const provider = createCredentialProvider({ wallet: walletClient.getWallet() }); + const sdkCredentials = await provider.getCredentials(); + expect(sdkCredentials.length).toBeGreaterThan(0); + + const importedId = importResult.credential?.id; + if (importedId) { + const inSdkStore = sdkCredentials.some((doc: any) => { + const id = doc?.id || doc?.credential?.id; + return id === importedId; + }); + expect(inSdkStore).toBe(true); + } + }); + }); }); diff --git a/apps/wallet-server/src/features/dids/client.ts b/apps/wallet-server/src/features/dids/client.ts index c18a2a5..16abc6f 100644 --- a/apps/wallet-server/src/features/dids/client.ts +++ b/apps/wallet-server/src/features/dids/client.ts @@ -3,9 +3,8 @@ * Manages DID operations using the Dock Wallet SDK */ -import { createDIDProvider } from "@docknetwork/wallet-sdk-core/lib/did-provider"; -import type { IDIDProvider } from "@docknetwork/wallet-sdk-core/lib/types"; -import type { IWallet } from "@docknetwork/wallet-sdk-core/lib/types"; +import type { IDIDProvider } from "@docknetwork/wallet-sdk-core/lib/types.js"; +import type { IWallet } from "@docknetwork/wallet-sdk-core/lib/types.js"; import type { CreateDIDResult, DIDListResult } from "./types.js"; export class DIDClient { @@ -19,8 +18,9 @@ export class DIDClient { /** * Initialize the DID provider */ - private ensureProvider(): IDIDProvider { + private async ensureProvider(): Promise { if (!this.didProvider) { + const { createDIDProvider } = await import("@docknetwork/wallet-sdk-core/lib/did-provider.js"); this.didProvider = createDIDProvider({ wallet: this.wallet }); } return this.didProvider; @@ -30,7 +30,7 @@ export class DIDClient { * Get the default DID for this wallet */ async getDefaultDID(): Promise { - const provider = this.ensureProvider(); + const provider = await this.ensureProvider(); const allDocs = await provider.getAll(); // Filter to only DID resolution documents and extract the DID @@ -46,7 +46,7 @@ export class DIDClient { * Create a new DID */ async createDID(keyType?: string): Promise { - const provider = this.ensureProvider(); + const provider = await this.ensureProvider(); // Create DID using the provider const result = await provider.createDIDKey({ @@ -65,7 +65,7 @@ export class DIDClient { * List all DIDs in the wallet */ async listDIDs(): Promise { - const provider = this.ensureProvider(); + const provider = await this.ensureProvider(); const allDocs = await provider.getAll(); // Filter to only DID resolution documents and extract the DID diff --git a/apps/wallet-server/src/features/dids/tests/integration/dids-client.test.ts b/apps/wallet-server/src/features/dids/tests/integration/dids-client.test.ts index 91810f8..2142ccd 100644 --- a/apps/wallet-server/src/features/dids/tests/integration/dids-client.test.ts +++ b/apps/wallet-server/src/features/dids/tests/integration/dids-client.test.ts @@ -23,6 +23,10 @@ describe("integration: DIDClient with real Wallet SDK", () => { }); afterEach(async () => { + if (walletClient) { + await walletClient.waitForIdle(); + } + // Clean up wallet resources after each test if (walletClient && walletClient.isInitialized()) { try { @@ -31,8 +35,6 @@ describe("integration: DIDClient with real Wallet SDK", () => { console.error("Error cleaning up wallet:", error); } } - // Wait for remaining async operations to complete - await new Promise((resolve) => setTimeout(resolve, 100)); }); describe("getDefaultDID", () => { diff --git a/apps/wallet-server/src/features/dids/tests/unit/dids-tools.test.ts b/apps/wallet-server/src/features/dids/tests/unit/dids-tools.test.ts index ae93a85..52460ea 100644 --- a/apps/wallet-server/src/features/dids/tests/unit/dids-tools.test.ts +++ b/apps/wallet-server/src/features/dids/tests/unit/dids-tools.test.ts @@ -252,7 +252,7 @@ describe("unit: DID tools", () => { }); // Test each handler returns proper structure - for (const [name, handler] of handlers.entries()) { + for (const [_name, handler] of handlers.entries()) { const result = await handler({}); expect(result).toHaveProperty("content"); diff --git a/apps/wallet-server/src/index.ts b/apps/wallet-server/src/index.ts index cecc19e..a4f81bc 100644 --- a/apps/wallet-server/src/index.ts +++ b/apps/wallet-server/src/index.ts @@ -1,7 +1,6 @@ import "dotenv/config"; import { bootstrapMCPServer } from "@truvera/mcp-shared/server"; import { BUILD_INFO } from "./build-info.js"; -import { createDIDProvider } from "@docknetwork/wallet-sdk-core/lib/did-provider"; import { WalletClient } from "./wallet-client.js"; import { DIDClient, didToolDefs, getDIDHandlers } from "./features/dids/index.js"; import { CredentialClient, credentialToolDefs, getCredentialHandlers } from "./features/credentials/index.js"; @@ -26,10 +25,7 @@ async function initializeClients() { const wallet = walletClient.getWallet(); const didClient = new DIDClient(wallet); - - // Create DID provider for credential import - const didProvider = createDIDProvider({ wallet }); - const credentialClient = new CredentialClient(wallet, didProvider); + const credentialClient = new CredentialClient(wallet); return { walletClient, didClient, credentialClient }; } diff --git a/apps/wallet-server/src/tests/helpers/live-test-gate.ts b/apps/wallet-server/src/tests/helpers/live-test-gate.ts new file mode 100644 index 0000000..c271b4e --- /dev/null +++ b/apps/wallet-server/src/tests/helpers/live-test-gate.ts @@ -0,0 +1,31 @@ +import dotenv from "dotenv"; + +dotenv.config(); +dotenv.config({ path: ".env.test", override: true }); +dotenv.config({ path: ".env.tests", override: true }); + +const LIVE_MODE = process.env.TRUVERA_RUN_LIVE_TESTS === "true"; +const API_KEY = process.env.TRUVERA_API_KEY; + +export const TRUVERA_API_ENDPOINT = + process.env.TRUVERA_API_ENDPOINT || "https://api-testnet.truvera.io"; + +export const liveApiKey = API_KEY; + +export const shouldRunLiveTests = LIVE_MODE && !!API_KEY; + +export const liveTestSkipReason = !LIVE_MODE + ? "TRUVERA_RUN_LIVE_TESTS=true is required to run live tests" + : !API_KEY + ? "TRUVERA_API_KEY is required to run live tests" + : undefined; + +/** + * Call at the start of a `beforeAll` to make the suite fail loudly instead of + * silently skipping when live-test env vars are not configured. + */ +export function requireLiveTestEnv(): void { + if (liveTestSkipReason) { + throw new Error(`Live test env not configured: ${liveTestSkipReason}`); + } +} diff --git a/apps/wallet-server/src/wallet-client.ts b/apps/wallet-server/src/wallet-client.ts index da6c6c7..38e42ba 100644 --- a/apps/wallet-server/src/wallet-client.ts +++ b/apps/wallet-server/src/wallet-client.ts @@ -3,8 +3,8 @@ * Manages wallet initialization and lifecycle */ -import { createDataStore as createBaseDataStore } from "@docknetwork/wallet-sdk-data-store/lib/index"; -import type { DataStore, LocalStorage } from "@docknetwork/wallet-sdk-data-store/lib/types"; +import { createDataStore as createBaseDataStore } from "@docknetwork/wallet-sdk-data-store/lib/index.js"; +import type { DataStore, LocalStorage } from "@docknetwork/wallet-sdk-data-store/lib/types.js"; import { createDocument, removeDocument, @@ -15,14 +15,14 @@ import { getAllDocuments, removeAllDocuments, getDocumentCorrelations, -} from "@docknetwork/wallet-sdk-data-store-web/lib/entities/document"; +} from "@docknetwork/wallet-sdk-data-store-web/lib/entities/document/index.js"; import { createWallet as createWalletRecord, getWallet, updateWallet, -} from "@docknetwork/wallet-sdk-data-store-web/lib/entities/wallet.entity"; -import { createWallet } from "@docknetwork/wallet-sdk-core/lib/wallet"; -import type { IWallet } from "@docknetwork/wallet-sdk-core/lib/types"; +} from "@docknetwork/wallet-sdk-data-store-web/lib/entities/wallet.entity.js"; +import { createWallet } from "@docknetwork/wallet-sdk-core/lib/wallet.js"; +import type { IWallet } from "@docknetwork/wallet-sdk-core/lib/types.js"; class InMemoryLocalStorage implements LocalStorage { private readonly storage = new Map(); @@ -45,12 +45,64 @@ export class WalletClient { private walletName: string; private networkId: string; private dataStore: DataStore | null = null; + private inFlightDocumentOps = 0; + private idleWaiters: Array<() => void> = []; constructor(walletName: string = "default-wallet", networkId: string = "testnet") { this.walletName = walletName; this.networkId = networkId; } + private trackDocumentOperation(operation: Promise): Promise { + this.inFlightDocumentOps += 1; + + return operation.finally(() => { + this.inFlightDocumentOps = Math.max(0, this.inFlightDocumentOps - 1); + + if (this.inFlightDocumentOps === 0) { + const waiters = this.idleWaiters.splice(0); + for (const resolve of waiters) { + resolve(); + } + } + }); + } + + /** + * Wait until tracked document operations settle. + * This avoids brittle fixed sleeps in integration tests. + */ + async waitForIdle(timeoutMs: number = 10000): Promise { + const start = Date.now(); + + while (true) { + if (this.inFlightDocumentOps === 0) { + // Ensure no new operations were queued in the same tick. + await new Promise((resolve) => setImmediate(resolve)); + if (this.inFlightDocumentOps === 0) { + return; + } + } + + const elapsed = Date.now() - start; + const remaining = timeoutMs - elapsed; + if (remaining <= 0) { + throw new Error(`Timed out waiting for wallet document operations to settle after ${timeoutMs}ms`); + } + + await new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + reject(new Error(`Timed out waiting for wallet document operations to settle after ${timeoutMs}ms`)); + }, remaining); + + this.idleWaiters.push(() => { + clearTimeout(timeoutId); + resolve(); + }); + }); + } + } + /** * Initialize the wallet */ @@ -75,14 +127,14 @@ export class WalletClient { }, dataSource, documentStore: { - addDocument: (json, options) => createDocument({ dataStore, json, options }), - removeDocument: (id, options) => removeDocument({ dataStore, id, options }), - updateDocument: (document, options) => updateDocument({ dataStore, document, options }), + addDocument: (json, options) => this.trackDocumentOperation(createDocument({ dataStore, json, options })), + removeDocument: (id, options) => this.trackDocumentOperation(removeDocument({ dataStore, id, options })), + updateDocument: (document, options) => this.trackDocumentOperation(updateDocument({ dataStore, document, options })), getDocumentById: (id) => getDocumentById({ dataStore, id }), getDocumentsByType: (type) => getDocumentsByType({ dataStore, type }), getDocumentsById: (idList) => getDocumentsById({ dataStore, idList }), getAllDocuments: (allNetworks) => getAllDocuments({ dataStore, allNetworks }), - removeAllDocuments: () => removeAllDocuments({ dataStore }), + removeAllDocuments: () => this.trackDocumentOperation(removeAllDocuments({ dataStore })), getDocumentCorrelations: (documentId) => getDocumentCorrelations({ dataStore, documentId }), }, localStorageImpl, @@ -161,14 +213,13 @@ export class WalletClient { // Call wallet cleanup try { + await this.waitForIdle(); await this.wallet.deleteWallet(); + await this.waitForIdle(); } catch (err) { console.debug("Error in wallet.deleteWallet():", err); } - // Wait for async operations to settle before cleanup - await new Promise((resolve) => setTimeout(resolve, 100)); - // Null out references to allow garbage collection this.wallet = null; this.dataStore = null; diff --git a/docker-compose.yml b/docker-compose.yml index 69e1be2..5c1df35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,24 @@ services: networks: - mcp-network + wallet-mcp-service: + build: + context: . + dockerfile: apps/wallet-server/Dockerfile + container_name: wallet-mcp-service + environment: + - WALLET_MASTER_KEY=${WALLET_MASTER_KEY} + - MCP_MODE=${MCP_MODE:-http} + - MCP_PORT=3001 + - CHEQD_NETWORK=${CHEQD_NETWORK:-testnet} + - WALLET_NAME=${WALLET_NAME:-mcp-wallet} + - NODE_ENV=production + ports: + - "3001:3001" + restart: unless-stopped + networks: + - mcp-network + networks: mcp-network: driver: bridge diff --git a/package-lock.json b/package-lock.json index b5b8723..37bfeb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,14 @@ "": { "name": "truvera-mcp-servers", "version": "1.0.0", + "hasInstallScript": true, "workspaces": [ "packages/*", "apps/*" ], + "devDependencies": { + "patch-package": "^8.0.1" + }, "engines": { "node": ">=18.0.0", "npm": ">=8.0.0" @@ -311,17 +315,22 @@ "version": "0.1.0", "dependencies": { "@docknetwork/wallet-sdk-core": "^1.7.0", + "@docknetwork/wallet-sdk-data-store": "^1.7.0", "@docknetwork/wallet-sdk-data-store-web": "^1.7.0", "@modelcontextprotocol/sdk": "^1.29.0", "@truvera/mcp-shared": "file:../../packages/mcp-shared", - "dotenv": "^16.6.1" + "dotenv": "^16.6.1", + "module-alias": "^2.2.3" }, "devDependencies": { "@babel/core": "^7.26.0", "@babel/preset-env": "^7.26.0", "@types/jest": "^29.5.14", "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", "babel-jest": "^29.7.0", + "eslint": "^10.0.2", "jest": "^29.7.0", "ts-jest": "^29.2.5", "tsx": "^4.7.0", @@ -723,6 +732,71 @@ "node": ">=12" } }, + "apps/wallet-server/node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "apps/wallet-server/node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "apps/wallet-server/node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "apps/wallet-server/node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "apps/wallet-server/node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, "apps/wallet-server/node_modules/@vitest/expect": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", @@ -797,6 +871,23 @@ "url": "https://opencollective.com/vitest" } }, + "apps/wallet-server/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "apps/wallet-server/node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -807,6 +898,29 @@ "node": "*" } }, + "apps/wallet-server/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "apps/wallet-server/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "apps/wallet-server/node_modules/chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", @@ -865,6 +979,145 @@ "@esbuild/win32-x64": "0.21.5" } }, + "apps/wallet-server/node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "apps/wallet-server/node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "apps/wallet-server/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "apps/wallet-server/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "apps/wallet-server/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "apps/wallet-server/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "apps/wallet-server/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "apps/wallet-server/node_modules/p-limit": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", @@ -2793,9 +3046,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2866,9 +3119,9 @@ } }, "node_modules/@borewit/text-codec": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", - "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", "license": "MIT", "funding": { "type": "github", @@ -2881,39 +3134,45 @@ "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@cedar-policy/cedar-wasm": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@cedar-policy/cedar-wasm/-/cedar-wasm-4.9.1.tgz", + "integrity": "sha512-7+57EYkWmkBGasBQU6UhdafwxrY+YXzBlxpYZn33s1YR978W6ZqgLEAvHb3Wg1XMIzLWWoljhFYerejpOpvxuA==", + "license": "Apache-2.0" + }, "node_modules/@cheqd/sdk": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@cheqd/sdk/-/sdk-5.3.2.tgz", - "integrity": "sha512-JRvhj8BZllMWtQEZCO1YKs1/QhVufvZyTNmfwNLiPvNWhjwkCookxU6E8xn9Vs/tCeMgNxlfrJTkPWcdE2DlMA==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@cheqd/sdk/-/sdk-5.4.3.tgz", + "integrity": "sha512-ewi08YKsOkqwlYlHg8ocxOhuuXQQprq9+XoGY5ZR+5i3zpw2CggDHiSPfSjrF8EhVFk0JcMo3vfFRoksdjpb8w==", "license": "Apache-2.0", "workspaces": [ "esm", "cjs" ], "dependencies": { - "@cheqd/ts-proto": "^4.1.1", - "@cheqd/ts-proto-cjs": "npm:@cheqd/ts-proto@~2.5.0", - "@cosmjs/amino": "^0.33.1", + "@cheqd/ts-proto": "^4.2.0", + "@cheqd/ts-proto-cjs": "npm:@cheqd/ts-proto@^2.6.0", + "@cosmjs/amino": "^0.36.2", "@cosmjs/amino-cjs": "npm:@cosmjs/amino@~0.30.1", - "@cosmjs/crypto": "^0.33.1", + "@cosmjs/crypto": "^0.36.2", "@cosmjs/crypto-cjs": "npm:@cosmjs/crypto@~0.30.1", - "@cosmjs/encoding": "^0.33.1", + "@cosmjs/encoding": "^0.36.2", "@cosmjs/encoding-cjs": "npm:@cosmjs/encoding@~0.30.1", - "@cosmjs/math": "^0.33.1", + "@cosmjs/math": "^0.36.2", "@cosmjs/math-cjs": "npm:@cosmjs/math@~0.30.1", - "@cosmjs/proto-signing": "^0.33.1", + "@cosmjs/proto-signing": "^0.36.2", "@cosmjs/proto-signing-cjs": "npm:@cosmjs/proto-signing@~0.30.1", - "@cosmjs/stargate": "^0.33.1", + "@cosmjs/stargate": "^0.36.2", "@cosmjs/stargate-cjs": "npm:@cosmjs/stargate@~0.30.1", - "@cosmjs/tendermint-rpc": "^0.33.1", + "@cosmjs/tendermint-rpc": "^0.36.2", "@cosmjs/tendermint-rpc-cjs": "npm:@cosmjs/tendermint-rpc@~0.30.1", - "@cosmjs/utils": "^0.33.1", + "@cosmjs/utils": "^0.36.2", "@cosmjs/utils-cjs": "npm:@cosmjs/utils@~0.30.1", "@stablelib/ed25519": "^2.0.2", "@stablelib/ed25519-cjs": "npm:@stablelib/ed25519@^1.0.3", "@types/secp256k1": "^4.0.6", "@types/secp256k1-cjs": "npm:@types/secp256k1@^4.0.6", - "cosmjs-types": "^0.9.0", + "cosmjs-types": "^0.10.1", "cosmjs-types-cjs": "npm:cosmjs-types@^0.7.2", "did-jwt": "^8.0.16", "did-jwt-cjs": "npm:did-jwt@^8.0.15", @@ -2930,7 +3189,7 @@ "secp256k1-cjs": "npm:secp256k1@^5.0.1", "uint8arrays": "^5.1.0", "uint8arrays-cjs": "npm:uint8arrays@^3.1.1", - "uuid": "^11.1.0", + "uuid": "^13.0.0", "uuid-cjs": "npm:uuid@~10.0.0" }, "engines": { @@ -2938,37 +3197,36 @@ } }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/amino": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.33.1.tgz", - "integrity": "sha512-WfWiBf2EbIWpwKG9AOcsIIkR717SY+JdlXM/SL/bI66BdrhniAF+/ZNis9Vo9HF6lP2UU5XrSmFA4snAvEgdrg==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.36.2.tgz", + "integrity": "sha512-r4yV1bhl412gwHGlyaUaJHIJnmldtyGsAwyz3oHHVxduiECj06Rv6wqeyLZfQa9W6hU+MlZwy7LabSUkkyGwjA==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/crypto": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1" + "@cosmjs/crypto": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2" } }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/crypto": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.33.1.tgz", - "integrity": "sha512-U4kGIj/SNBzlb2FGgA0sMR0MapVgJUg8N+oIAiN5+vl4GZ3aefmoL1RDyTrFS/7HrB+M+MtHsxC0tvEu4ic/zA==", - "deprecated": "This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk.", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.36.2.tgz", + "integrity": "sha512-QL4NHtcqR6DEKIN200aLeR8gKO433K0f5avKV0TVFP/g12UtnEGSk79PJq5Gv1PLc9GtATHgLLQI/3D8TEe+ig==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "@noble/hashes": "^1", - "bn.js": "^5.2.0", - "elliptic": "^6.6.1", - "libsodium-wrappers-sumo": "^0.7.11" + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.2", + "@noble/hashes": "^1.8.0", + "hash-wasm": "^4.12.0" } }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/encoding": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.33.1.tgz", - "integrity": "sha512-nuNxf29fUcQE14+1p//VVQDwd1iau5lhaW/7uMz7V2AH3GJbFJoJVaKvVyZvdFk+Cnu+s3wCqgq4gJkhRCJfKw==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.36.2.tgz", + "integrity": "sha512-i3+P1EKYoLcONAsmpJPhDAc3Wh3ajZNRHt/hczi/JEQXmleTJLVzv2mXUyllM6Qa+B6ybbr3Z2lnEFa8L3yLqg==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -2977,43 +3235,59 @@ } }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/math": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.33.1.tgz", - "integrity": "sha512-ytGkWdKFCPiiBU5eqjHNd59djPpIsOjbr2CkNjlnI1Zmdj+HDkSoD9MUGpz9/RJvRir5IvsXqdE05x8EtoQkJA==", - "license": "Apache-2.0", - "dependencies": { - "bn.js": "^5.2.0" - } + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.36.2.tgz", + "integrity": "sha512-uJZRzxqnBk3MgxFgeyUwLgUzWkAIcmznWSB/tgGCjGCnUNebzI+44dA3ncEDCMqQysi/MZ+cSwAcDU7IY2PFeA==", + "license": "Apache-2.0" }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/proto-signing": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.33.1.tgz", - "integrity": "sha512-Sv4W+MxX+0LVnd+2rU4Fw1HRsmMwSVSYULj7pRkij3wnPwUlTVoJjmKFgKz13ooIlfzPrz/dnNjGp/xnmXChFQ==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.36.2.tgz", + "integrity": "sha512-dyZsgZBQgGkaE4cazHVX8GDwrRJVKUVDnrODkyFXVNbxMnm4t6nxpK1qwgY9GHlWUhck3Dh9NT3BoMbXiMYTZQ==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/amino": "^0.33.1", - "@cosmjs/crypto": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "cosmjs-types": "^0.9.0" + "@cosmjs/amino": "^0.36.2", + "@cosmjs/crypto": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "cosmjs-types": "^0.10.1" } }, "node_modules/@cheqd/sdk/node_modules/@cosmjs/utils": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.33.1.tgz", - "integrity": "sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.36.2.tgz", + "integrity": "sha512-OOr2HU/Ph+/GI1Fx2UCf3LOyX9YTCP51d2HitTOjjEJRYnkfKXP3lMBl1FZo5QaFWxnfuBc+Cj+cSoiQUJRyzQ==", "license": "Apache-2.0" }, + "node_modules/@cheqd/sdk/node_modules/cosmjs-types": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.10.1.tgz", + "integrity": "sha512-CENXb4O5GN+VyB68HYXFT2SOhv126Z59631rZC56m8uMWa6/cSlFeai8BwZGT1NMepw0Ecf+U8XSOnBzZUWh9Q==", + "license": "Apache-2.0" + }, + "node_modules/@cheqd/sdk/node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/@cheqd/ts-proto": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@cheqd/ts-proto/-/ts-proto-4.2.0.tgz", - "integrity": "sha512-0/pKFSDtERs5euLW0mcry3Lr9mguDY3Sr+W9uzs7Iru6HEBxs+LjwcpaFr9073wlsKF9fLhsCDHvDJDwNxePkg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@cheqd/ts-proto/-/ts-proto-4.2.1.tgz", + "integrity": "sha512-8O15Qaj/lyb/zNsKlUfP79XDnZw7lEToeONV8ji04AkFKf+hzPQNXhTMWp7Wf/vywUEzrHYZa1I4DITT6QmCJA==", "license": "Apache-2.0", "dependencies": { "@bufbuild/protobuf": "^2.5.1", "long": "^5.3.2", - "protobufjs": "^7.5.3" + "protobufjs": "^8.0.0" }, "engines": { "node": ">=22.0.0" @@ -3021,9 +3295,9 @@ }, "node_modules/@cheqd/ts-proto-cjs": { "name": "@cheqd/ts-proto", - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@cheqd/ts-proto/-/ts-proto-2.5.0.tgz", - "integrity": "sha512-3KqyvcruFxvkz+p6LnSCyUnqBJ2bJeOnIDkaYoAMcmGcSNKti3VECOKGdjjEO3rG/0/gAR9bhEHu9j1mUKSFqA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@cheqd/ts-proto/-/ts-proto-2.6.0.tgz", + "integrity": "sha512-0hbAFZzt4jvEQqCp0SjSM05f0l5HR4MhrWdlF4bk1jmHAz8U/FgCqXTBIJZ9nGG7RASX9t9MPbmhPOh6ED+4ow==", "license": "Apache-2.0", "dependencies": { "@bufbuild/protobuf": "^2.2.2", @@ -3034,6 +3308,30 @@ "node": ">=20" } }, + "node_modules/@cheqd/ts-proto-cjs/node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", @@ -3236,12 +3534,12 @@ } }, "node_modules/@cosmjs/json-rpc": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.33.1.tgz", - "integrity": "sha512-T6VtWzecpmuTuMRGZWuBYHsMF/aznWCYUt/cGMWNSz7DBPipVd0w774PKpxXzpEbyt5sr61NiuLXc+Az15S/Cw==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.36.2.tgz", + "integrity": "sha512-3IRamylHVCxBevXGlnIoWUdJCLsP5LwHbXYUsBnC9T8UttZ5oYRN5gDf6+2dQEPk+p9xOv2i8xrCwNWxo7675Q==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/stream": "^0.33.1", + "@cosmjs/stream": "^0.36.2", "xstream": "^11.14.0" } }, @@ -3391,31 +3689,31 @@ } }, "node_modules/@cosmjs/socket": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.33.1.tgz", - "integrity": "sha512-KzAeorten6Vn20sMiM6NNWfgc7jbyVo4Zmxev1FXa5EaoLCZy48cmT3hJxUJQvJP/lAy8wPGEjZ/u4rmF11x9A==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.36.2.tgz", + "integrity": "sha512-Pb7JcTFWnq6yfY0IEejHrpSxNDJYcqjjAa1D29a6b/obk4qa4o3oIV5bIx6zAbdRq8uLoBfvWs0bHTNnVuBWJg==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/stream": "^0.33.1", + "@cosmjs/stream": "^0.36.2", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stargate": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.33.1.tgz", - "integrity": "sha512-CnJ1zpSiaZgkvhk+9aTp5IPmgWn2uo+cNEBN8VuD9sD6BA0V4DMjqe251cNFLiMhkGtiE5I/WXFERbLPww3k8g==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.36.2.tgz", + "integrity": "sha512-vnNK4dXF+s2v1aKPfYxKVrvXPcnBQb8rPoBScnTpPWnRt3XXbLw7Oo6fTQQWwKYNKQzi6DOApeEB+bCYcaPAAw==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/amino": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/proto-signing": "^0.33.1", - "@cosmjs/stream": "^0.33.1", - "@cosmjs/tendermint-rpc": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "cosmjs-types": "^0.9.0" + "@cosmjs/amino": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/proto-signing": "^0.36.2", + "@cosmjs/stream": "^0.36.2", + "@cosmjs/tendermint-rpc": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "cosmjs-types": "^0.10.1" } }, "node_modules/@cosmjs/stargate-cjs": { @@ -3609,37 +3907,36 @@ } }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/amino": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.33.1.tgz", - "integrity": "sha512-WfWiBf2EbIWpwKG9AOcsIIkR717SY+JdlXM/SL/bI66BdrhniAF+/ZNis9Vo9HF6lP2UU5XrSmFA4snAvEgdrg==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.36.2.tgz", + "integrity": "sha512-r4yV1bhl412gwHGlyaUaJHIJnmldtyGsAwyz3oHHVxduiECj06Rv6wqeyLZfQa9W6hU+MlZwy7LabSUkkyGwjA==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/crypto": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1" + "@cosmjs/crypto": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2" } }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/crypto": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.33.1.tgz", - "integrity": "sha512-U4kGIj/SNBzlb2FGgA0sMR0MapVgJUg8N+oIAiN5+vl4GZ3aefmoL1RDyTrFS/7HrB+M+MtHsxC0tvEu4ic/zA==", - "deprecated": "This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk.", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.36.2.tgz", + "integrity": "sha512-QL4NHtcqR6DEKIN200aLeR8gKO433K0f5avKV0TVFP/g12UtnEGSk79PJq5Gv1PLc9GtATHgLLQI/3D8TEe+ig==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "@noble/hashes": "^1", - "bn.js": "^5.2.0", - "elliptic": "^6.6.1", - "libsodium-wrappers-sumo": "^0.7.11" + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.2", + "@noble/hashes": "^1.8.0", + "hash-wasm": "^4.12.0" } }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/encoding": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.33.1.tgz", - "integrity": "sha512-nuNxf29fUcQE14+1p//VVQDwd1iau5lhaW/7uMz7V2AH3GJbFJoJVaKvVyZvdFk+Cnu+s3wCqgq4gJkhRCJfKw==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.36.2.tgz", + "integrity": "sha512-i3+P1EKYoLcONAsmpJPhDAc3Wh3ajZNRHt/hczi/JEQXmleTJLVzv2mXUyllM6Qa+B6ybbr3Z2lnEFa8L3yLqg==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -3648,57 +3945,59 @@ } }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/math": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.33.1.tgz", - "integrity": "sha512-ytGkWdKFCPiiBU5eqjHNd59djPpIsOjbr2CkNjlnI1Zmdj+HDkSoD9MUGpz9/RJvRir5IvsXqdE05x8EtoQkJA==", - "license": "Apache-2.0", - "dependencies": { - "bn.js": "^5.2.0" - } + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.36.2.tgz", + "integrity": "sha512-uJZRzxqnBk3MgxFgeyUwLgUzWkAIcmznWSB/tgGCjGCnUNebzI+44dA3ncEDCMqQysi/MZ+cSwAcDU7IY2PFeA==", + "license": "Apache-2.0" }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/proto-signing": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.33.1.tgz", - "integrity": "sha512-Sv4W+MxX+0LVnd+2rU4Fw1HRsmMwSVSYULj7pRkij3wnPwUlTVoJjmKFgKz13ooIlfzPrz/dnNjGp/xnmXChFQ==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.36.2.tgz", + "integrity": "sha512-dyZsgZBQgGkaE4cazHVX8GDwrRJVKUVDnrODkyFXVNbxMnm4t6nxpK1qwgY9GHlWUhck3Dh9NT3BoMbXiMYTZQ==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/amino": "^0.33.1", - "@cosmjs/crypto": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "cosmjs-types": "^0.9.0" + "@cosmjs/amino": "^0.36.2", + "@cosmjs/crypto": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "cosmjs-types": "^0.10.1" } }, "node_modules/@cosmjs/stargate/node_modules/@cosmjs/utils": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.33.1.tgz", - "integrity": "sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.36.2.tgz", + "integrity": "sha512-OOr2HU/Ph+/GI1Fx2UCf3LOyX9YTCP51d2HitTOjjEJRYnkfKXP3lMBl1FZo5QaFWxnfuBc+Cj+cSoiQUJRyzQ==", + "license": "Apache-2.0" + }, + "node_modules/@cosmjs/stargate/node_modules/cosmjs-types": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.10.1.tgz", + "integrity": "sha512-CENXb4O5GN+VyB68HYXFT2SOhv126Z59631rZC56m8uMWa6/cSlFeai8BwZGT1NMepw0Ecf+U8XSOnBzZUWh9Q==", "license": "Apache-2.0" }, "node_modules/@cosmjs/stream": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.33.1.tgz", - "integrity": "sha512-bMUvEENjeQPSTx+YRzVsWT1uFIdHRcf4brsc14SOoRQ/j5rOJM/aHfsf/BmdSAnYbdOQ3CMKj/8nGAQ7xUdn7w==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.36.2.tgz", + "integrity": "sha512-FlZx2Buovem837LdTLPkPFcxzuQ7zierAqSXwMPr/MG3k+qMxHNfLFTTCXMNWQ4ZlbYedud8ZqCL3/HKdS5mig==", "license": "Apache-2.0", "dependencies": { "xstream": "^11.14.0" } }, "node_modules/@cosmjs/tendermint-rpc": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.33.1.tgz", - "integrity": "sha512-22klDFq2MWnf//C8+rZ5/dYatr6jeGT+BmVbutXYfAK9fmODbtFcumyvB6uWaEORWfNukl8YK1OLuaWezoQvxA==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.36.2.tgz", + "integrity": "sha512-76Z99C1NVf/Yv/1bWU0wul8MhRwVdqiZxqU5bcHqvJLoQ2nKUfGpSSYRdbMHfZ63J8ryRqQ95uPvPTfrBb+agw==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/crypto": "^0.33.1", - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/json-rpc": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/socket": "^0.33.1", - "@cosmjs/stream": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "axios": "^1.6.0", + "@cosmjs/crypto": "^0.36.2", + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/json-rpc": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/socket": "^0.36.2", + "@cosmjs/stream": "^0.36.2", + "@cosmjs/utils": "^0.36.2", "readonly-date": "^1.0.0", "xstream": "^11.14.0" } @@ -3805,25 +4104,24 @@ } }, "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/crypto": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.33.1.tgz", - "integrity": "sha512-U4kGIj/SNBzlb2FGgA0sMR0MapVgJUg8N+oIAiN5+vl4GZ3aefmoL1RDyTrFS/7HrB+M+MtHsxC0tvEu4ic/zA==", - "deprecated": "This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk.", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.36.2.tgz", + "integrity": "sha512-QL4NHtcqR6DEKIN200aLeR8gKO433K0f5avKV0TVFP/g12UtnEGSk79PJq5Gv1PLc9GtATHgLLQI/3D8TEe+ig==", "license": "Apache-2.0", "dependencies": { - "@cosmjs/encoding": "^0.33.1", - "@cosmjs/math": "^0.33.1", - "@cosmjs/utils": "^0.33.1", - "@noble/hashes": "^1", - "bn.js": "^5.2.0", - "elliptic": "^6.6.1", - "libsodium-wrappers-sumo": "^0.7.11" + "@cosmjs/encoding": "^0.36.2", + "@cosmjs/math": "^0.36.2", + "@cosmjs/utils": "^0.36.2", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.2", + "@noble/hashes": "^1.8.0", + "hash-wasm": "^4.12.0" } }, "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/encoding": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.33.1.tgz", - "integrity": "sha512-nuNxf29fUcQE14+1p//VVQDwd1iau5lhaW/7uMz7V2AH3GJbFJoJVaKvVyZvdFk+Cnu+s3wCqgq4gJkhRCJfKw==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.36.2.tgz", + "integrity": "sha512-i3+P1EKYoLcONAsmpJPhDAc3Wh3ajZNRHt/hczi/JEQXmleTJLVzv2mXUyllM6Qa+B6ybbr3Z2lnEFa8L3yLqg==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -3832,31 +4130,17 @@ } }, "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/math": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.33.1.tgz", - "integrity": "sha512-ytGkWdKFCPiiBU5eqjHNd59djPpIsOjbr2CkNjlnI1Zmdj+HDkSoD9MUGpz9/RJvRir5IvsXqdE05x8EtoQkJA==", - "license": "Apache-2.0", - "dependencies": { - "bn.js": "^5.2.0" - } + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.36.2.tgz", + "integrity": "sha512-uJZRzxqnBk3MgxFgeyUwLgUzWkAIcmznWSB/tgGCjGCnUNebzI+44dA3ncEDCMqQysi/MZ+cSwAcDU7IY2PFeA==", + "license": "Apache-2.0" }, "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/utils": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.33.1.tgz", - "integrity": "sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.36.2.tgz", + "integrity": "sha512-OOr2HU/Ph+/GI1Fx2UCf3LOyX9YTCP51d2HitTOjjEJRYnkfKXP3lMBl1FZo5QaFWxnfuBc+Cj+cSoiQUJRyzQ==", "license": "Apache-2.0" }, - "node_modules/@cosmjs/tendermint-rpc/node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/@cosmjs/utils": { "version": "0.32.4", "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.4.tgz", @@ -4319,20 +4603,20 @@ } }, "node_modules/@docknetwork/cheqd-blockchain-api": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@docknetwork/cheqd-blockchain-api/-/cheqd-blockchain-api-4.0.5.tgz", - "integrity": "sha512-frmo7jDk/NS9RlcuXBRD7tGieDEVgdRvTUsTIPZ0/AEyZWsM0eNEGSmxsTtwyh3Wi9Nra+g4lB5tl9PxyeQSZQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@docknetwork/cheqd-blockchain-api/-/cheqd-blockchain-api-4.1.1.tgz", + "integrity": "sha512-I1YsexfImHltf27x+p54hIMED2a3y+rprJgPmQeqrPt2mGQstjTVZUQLcetxyYmWqpt11L/RUefVGcSJSm1UIQ==", "license": "MIT", "dependencies": { - "@cheqd/sdk": "5.3.2", - "@cheqd/ts-proto": "^4.1.0", + "@cheqd/sdk": "5.4.3", + "@cheqd/ts-proto": "^4.2.0", "p-limit": "^6.1.0" }, "engines": { "node": ">=22.0.0" }, "peerDependencies": { - "@docknetwork/credential-sdk": "^0.54.6" + "@docknetwork/credential-sdk": "^0.54.11" } }, "node_modules/@docknetwork/cheqd-blockchain-api/node_modules/p-limit": { @@ -4363,26 +4647,29 @@ } }, "node_modules/@docknetwork/cheqd-blockchain-modules": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@docknetwork/cheqd-blockchain-modules/-/cheqd-blockchain-modules-4.0.6.tgz", - "integrity": "sha512-flHN0YTBUUUfXx6ZjP7RFKu2VrpnIfbNOzyZiMNVuESuGIS3mdp0TOsiCkY2bkd2DGipHaQYwxpyLesU3L0jZg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@docknetwork/cheqd-blockchain-modules/-/cheqd-blockchain-modules-4.0.8.tgz", + "integrity": "sha512-c/fO+Ar9nMgbB0+ME3mDRvWaFkvrcuLRQerA04NxpRLXKgq2Jth0r9pzRSJWiHM6bDmM0qdeXS7BSVq+iY0K9g==", "license": "MIT", "engines": { "node": ">=22.0.0" }, "peerDependencies": { - "@docknetwork/credential-sdk": "^0.54.9" + "@docknetwork/credential-sdk": "^0.54.11" } }, "node_modules/@docknetwork/credential-sdk": { - "version": "0.54.9", - "resolved": "https://registry.npmjs.org/@docknetwork/credential-sdk/-/credential-sdk-0.54.9.tgz", - "integrity": "sha512-Sq7mxjDpF5KCmQYlZqSIVPVgYFRdyd3JR0nqcHfocnzeeeahuHFT0APfXff3JXpd+QTjVPhkNHLNCDZo/+B8jQ==", + "version": "0.54.16", + "resolved": "https://registry.npmjs.org/@docknetwork/credential-sdk/-/credential-sdk-0.54.16.tgz", + "integrity": "sha512-A+EcOssWCvHYtmLwWdWIsQlRXI0tLJx2ZezZH8zWF/bpERIJCka/hRMy8OQwBfPoOMOTz8Og/HgGnLkD/mlZ4g==", "license": "MIT", "dependencies": { + "@astronautlabs/jsonpath": "^1.1.2", "@digitalcredentials/vc-status-list": "^9.0.0", "@docknetwork/crypto-wasm-ts": "^0.63.0", + "@docknetwork/vc-delegation-engine": "1.0.3", "@juanelas/base64": "^1.1.5", + "@sphereon/pex": "^5.0.0-unstable.28", "@sphereon/ssi-sdk-ext.did-resolver-jwk": "^0.26.0", "@stablelib/ed25519": "^1.0.0", "@transmute/json-web-signature": "^0.7.0-unstable.82", @@ -4411,6 +4698,97 @@ "node": ">=22.0.0" } }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sd-jwt/decode": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sd-jwt/decode/-/decode-0.7.2.tgz", + "integrity": "sha512-dan2LSvK63SKwb62031G4r7TE4TaiI0EK1KbPXqS+LCXNkNDUHqhtYp9uOpj+grXceCsMtMa2f8VnUfsjmwHHg==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/types": "0.7.2", + "@sd-jwt/utils": "0.7.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sd-jwt/present": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sd-jwt/present/-/present-0.7.2.tgz", + "integrity": "sha512-mQV85u2+mLLy2VZ9Wx2zpaB6yTDnbhCfWkP7eeCrzJQHBKAAHko8GrylEFmLKewFIcajS/r4lT/zHOsCkp5pZw==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/decode": "0.7.2", + "@sd-jwt/types": "0.7.2", + "@sd-jwt/utils": "0.7.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sd-jwt/types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sd-jwt/types/-/types-0.7.2.tgz", + "integrity": "sha512-1NRKowiW0ZiB9SGLApLPBH4Xk8gDQJ+nA9NdZ+uy6MmJKLEwjuJxO7yTvRIv/jX/0/Ebh339S7Kq4RD2AiFuRg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sd-jwt/utils": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sd-jwt/utils/-/utils-0.7.2.tgz", + "integrity": "sha512-aMPY7uHRMgyI5PlDvEiIc+eBFGC1EM8OCQRiEjJ8HGN0pajWMYj0qwSw7pS90A49/DsYU1a5Zpvb7nyjgGH0Yg==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/types": "0.7.2", + "js-base64": "^3.7.6" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sphereon/pex": { + "version": "5.0.0-unstable.28", + "resolved": "https://registry.npmjs.org/@sphereon/pex/-/pex-5.0.0-unstable.28.tgz", + "integrity": "sha512-zxHCWAc7fKppS7XX0zxnI4TF+Rdjax8pHc3exrYzn3t59dlv5siEAeYdtFrWJT4UVB5wTGzIEufzV5r+tfjelg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@astronautlabs/jsonpath": "^1.1.2", + "@sd-jwt/decode": "^0.7.2", + "@sd-jwt/present": "^0.7.2", + "@sd-jwt/types": "^0.7.2", + "@sphereon/pex-models": "^2.3.1", + "@sphereon/ssi-types": "0.30.2-feature.mdoc.funke2.366", + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "jwt-decode": "^3.1.2", + "nanoid": "^3.3.7", + "uint8arrays": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sphereon/pex-models": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sphereon/pex-models/-/pex-models-2.3.2.tgz", + "integrity": "sha512-foFxfLkRwcn/MOp/eht46Q7wsvpQGlO7aowowIIb5Tz9u97kYZ2kz6K2h2ODxWuv5CRA7Q0MY8XUBGE2lfOhOQ==", + "license": "Apache-2.0" + }, + "node_modules/@docknetwork/credential-sdk/node_modules/@sphereon/ssi-types": { + "version": "0.30.2-feature.mdoc.funke2.366", + "resolved": "https://registry.npmjs.org/@sphereon/ssi-types/-/ssi-types-0.30.2-feature.mdoc.funke2.366.tgz", + "integrity": "sha512-PmfTIbBovxdg7d9RD4WTVsJQtIMk5kcZo5qrBpumyPqz4TFiuGIjjuen0tDtv/IAwXSiNXX51MOHGfssQLskZA==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/decode": "^0.7.2", + "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.10", + "debug": "^4.3.5", + "events": "^3.3.0", + "jwt-decode": "^3.1.2" + } + }, "node_modules/@docknetwork/credential-sdk/node_modules/@stablelib/ed25519": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", @@ -4449,12 +4827,44 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@docknetwork/credential-sdk/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@docknetwork/credential-sdk/node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "license": "MIT" + }, "node_modules/@docknetwork/credential-sdk/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", "license": "(Apache-2.0 AND MIT)" }, + "node_modules/@docknetwork/credential-sdk/node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } + }, "node_modules/@docknetwork/credential-sdk/node_modules/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", @@ -4511,13 +4921,28 @@ "@digitalbazaar/edv-client": "^11.3.2" } }, + "node_modules/@docknetwork/vc-delegation-engine": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@docknetwork/vc-delegation-engine/-/vc-delegation-engine-1.0.3.tgz", + "integrity": "sha512-cOSHvPd5z/UlYyYj5P+WMIEqTnZNU0Wv/sXrmg+45K8P4uq7gNgBwMvVpoOjGe/KonFheMSBhFHd51MXIeMl5w==", + "license": "ISC", + "dependencies": { + "base64url": "^3.0.1", + "jsonld": "^6.0.0", + "jsonpath-plus": "^10.1.0", + "rify": "^0.7.1" + }, + "peerDependencies": { + "@cedar-policy/cedar-wasm": "^4.5.0" + } + }, "node_modules/@docknetwork/wallet-sdk-core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-core/-/wallet-sdk-core-1.7.0.tgz", - "integrity": "sha512-GFq14g0pLq1vUxI9AEKvj1QJMPoXyGHKS1eRsJsvSjbaPjoGZuQqJaHQ17ZD1bcs8EZgryhCcT28rRMZ04Lp/Q==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-core/-/wallet-sdk-core-1.7.6.tgz", + "integrity": "sha512-jk+5oikQFj2PPdQcNbschBaD8j8UnFR/u17hRVaJYc/+g99JPOeJmluEAeZvBNwgVFCGUm16cmg9JESqpvSudA==", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", "dependencies": { - "@docknetwork/wallet-sdk-wasm": "^1.5.14", + "@docknetwork/wallet-sdk-wasm": "^1.7.6", "futoin-hkdf": "^1.5.3" }, "peerDependencies": { @@ -4528,13 +4953,12 @@ } }, "node_modules/@docknetwork/wallet-sdk-data-store": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-data-store/-/wallet-sdk-data-store-1.7.0.tgz", - "integrity": "sha512-39rF8Ix+aa3M+qh/oKNjRJ+7uf6zTygWzHaagLF02VbZq8c4Lxd50OhiA+7VY25cqFUD/08EbiF7msL7/qNV2A==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-data-store/-/wallet-sdk-data-store-1.7.6.tgz", + "integrity": "sha512-Bps19PIqEmFxwFgqaE65e8yHQz599AiQcVauBQyydYSNkYS/ftErQ0L5wxLoZKWIzbHwxFyvSPbe1d6dffTItg==", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", - "peer": true, "dependencies": { - "@docknetwork/wallet-sdk-wasm": "^1.7.0", + "@docknetwork/wallet-sdk-wasm": "^1.7.6", "uuid": "^8.3.2" }, "peerDependencies": { @@ -4542,12 +4966,12 @@ } }, "node_modules/@docknetwork/wallet-sdk-data-store-web": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-data-store-web/-/wallet-sdk-data-store-web-1.7.0.tgz", - "integrity": "sha512-8Xdhz3+qikdOvKbG+JAPDOFZgqvqGzKqqVxDb8u0uDkrOsrW2MWAWsnxqJziKDEGmrLbGcq8NC1KDTNlM3CfEg==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-data-store-web/-/wallet-sdk-data-store-web-1.7.6.tgz", + "integrity": "sha512-p4IAKTUbfmPAJTpkI11PIJ+wKEgBsKG4oDvrEMmOqp8Jqjtxh5avqkA50a+TBcpW9jFa1QKYiN62l8RFNV8Uug==", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", "dependencies": { - "@docknetwork/wallet-sdk-wasm": "^1.7.0", + "@docknetwork/wallet-sdk-wasm": "^1.7.6", "uuid": "^8.3.2" }, "peerDependencies": { @@ -4568,15 +4992,14 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", - "peer": true, "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@docknetwork/wallet-sdk-dids": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-dids/-/wallet-sdk-dids-1.7.0.tgz", - "integrity": "sha512-x4/3xja7Ubog4rcpY1jH4T/UW8pV+iWyPLy4kX0ZZNoL1lOpvIPwe2Ys982//gAeytiWSLEuvqCKiuuCVkMYPg==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-dids/-/wallet-sdk-dids-1.7.6.tgz", + "integrity": "sha512-Lvv5zvmEJISHJLmBNkNnrQ6ylc8WVZzBfJQEEjy1KuvT7eHhmtcvvZ5d5hgP1eVPONt+I+7BIbvMCJ/hrrmDaQ==", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", "dependencies": { "@digitalbazaar/did-method-key": "^2.0.0", @@ -4593,18 +5016,20 @@ } }, "node_modules/@docknetwork/wallet-sdk-wasm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-wasm/-/wallet-sdk-wasm-1.7.0.tgz", - "integrity": "sha512-XYfaqIMa50tQqD1iqmExk1Ra8IeJAaA293hUUButmOMkGDf55cwGAuogd5jJeTTMWyWSFx5phHtnayDhrMlGXA==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@docknetwork/wallet-sdk-wasm/-/wallet-sdk-wasm-1.7.6.tgz", + "integrity": "sha512-vf7+RW+m9B0rHk3U8x5EnFu9rgqK40A7s1/16KRHkR9KLPyn3fx591rR+5pFQpzLCfpXmI53v9VrS4vombmSCw==", "license": "https://github.com/docknetwork/wallet-sdk/LICENSE", "dependencies": { "@astronautlabs/jsonpath": "^1.1.2", + "@cedar-policy/cedar-wasm": "^4.5.0", "@cosmjs/proto-signing": "^0.32.4", - "@docknetwork/cheqd-blockchain-api": "4.0.5", - "@docknetwork/cheqd-blockchain-modules": "4.0.6", - "@docknetwork/credential-sdk": "0.54.9", + "@docknetwork/cheqd-blockchain-api": "4.1.1", + "@docknetwork/cheqd-blockchain-modules": "4.0.8", + "@docknetwork/credential-sdk": "0.54.16", "@docknetwork/universal-wallet": "^2.0.1", - "@docknetwork/wallet-sdk-dids": "^1.7.0", + "@docknetwork/vc-delegation-engine": "1.0.3", + "@docknetwork/wallet-sdk-dids": "^1.7.6", "@noble/hashes": "1.8.0", "@scure/bip39": "^1.6.0", "@sd-jwt/crypto-nodejs": "^0.15.0", @@ -4616,7 +5041,9 @@ "axios-retry": "^3.2.5", "base64url": "^3.0.1", "cwait": "1.1.2", + "futoin-hkdf": "^1.5.3", "json-rpc-2.0": "^0.2.16", + "jsonld": "^6.0.0", "p-limit": "2.3.0", "uuid": "^8.3.2", "winston": "^3.3.3" @@ -5325,9 +5752,9 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.12", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.12.tgz", - "integrity": "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==", + "version": "1.19.13", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.13.tgz", + "integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -5876,6 +6303,30 @@ "@js-joda/core": ">=1.11.0" } }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, "node_modules/@juanelas/base64": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.1.5.tgz", @@ -6693,6 +7144,16 @@ "format-util": "^1.0.5" } }, + "node_modules/@sphereon/kmp-mdoc-core": { + "version": "0.2.0-SNAPSHOT.10", + "resolved": "https://registry.npmjs.org/@sphereon/kmp-mdoc-core/-/kmp-mdoc-core-0.2.0-SNAPSHOT.10.tgz", + "integrity": "sha512-mHH7I6fWdztaNjguGJOLaerXWnQymQ/xKQ8NqClIXoI2PJNgmpQG6DxFcLRs1aYyWg1iY8bPliLJi41u94KdCA==", + "dependencies": { + "@js-joda/core": "5.6.3", + "@js-joda/timezone": "2.3.0", + "format-util": "^1.0.5" + } + }, "node_modules/@sphereon/oid4vc-common": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/@sphereon/oid4vc-common/-/oid4vc-common-0.16.0.tgz", @@ -7076,9 +7537,9 @@ "license": "MIT" }, "node_modules/@stablelib/ed25519": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-2.0.2.tgz", - "integrity": "sha512-d/lJ5sgzhtmpMIbKFWfev+i6WebBdIzzBpMzXtZdvUijoksjXosYFNqytoMj7cRshNj+/XTLYnnVMdZfd+penw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-2.1.0.tgz", + "integrity": "sha512-8GLWoJur9nJiErABKHs5MjceSiYJJ2n8QP9k8Q5x6GWU2y5oAQ6qzPh8kCgQy5aHlUxcmRA1frQ5Gu2bHoIDPw==", "license": "MIT", "dependencies": { "@stablelib/random": "^2.0.1", @@ -7669,9 +8130,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", "license": "MIT" }, "node_modules/@types/long": { @@ -8150,6 +8611,13 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -8444,12 +8912,6 @@ "node": ">= 0.4" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -8495,9 +8957,9 @@ } }, "node_modules/b4a": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.5.tgz", - "integrity": "sha512-iEsKNwDh1wiWTps1/hdkNdmBgDlDVZP5U57ZVOlt+dNFqpc/lpPouCIxZw+DYBgc4P9NDfIZMPNR4CHNhzwLIA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -9390,18 +9852,6 @@ "node": ">=12.20" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -9897,15 +10347,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -10216,9 +10657,9 @@ } }, "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -11212,9 +11653,9 @@ } }, "node_modules/file-type": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.0.tgz", - "integrity": "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==", + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", "license": "MIT", "dependencies": { "@tokenizer/inflate": "^0.4.1", @@ -11339,6 +11780,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -11433,43 +11884,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/format-util": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", @@ -12022,6 +12436,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", + "license": "MIT" + }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -12056,9 +12476,9 @@ } }, "node_modules/hono": { - "version": "4.12.11", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.11.tgz", - "integrity": "sha512-r4xbIa3mGGGoH9nN4A14DOg2wx7y2oQyJEb5O57C/xzETG/qx4c7CVDQ5WMeKHZ7ORk2W0hZ/sQKXTav3cmYBA==", + "version": "4.12.12", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.12.tgz", + "integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -12413,6 +12833,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -12705,6 +13141,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -13637,6 +14086,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -13697,6 +14155,26 @@ "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -13730,8 +14208,8 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "universalify": "^2.0.0" }, @@ -13739,6 +14217,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonld": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-6.0.0.tgz", @@ -13901,9 +14389,9 @@ } }, "node_modules/jsonpath": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", - "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.3.0.tgz", + "integrity": "sha512-0kjkYHJBkAy50Z5QzArZ7udmvxrJzkpKYW27fiF//BrMY7TQibYLl+FYIXN2BiYmwMIVzSfD8aDRj6IzgBX2/w==", "license": "MIT", "dependencies": { "esprima": "1.2.5", @@ -13911,6 +14399,24 @@ "underscore": "1.13.6" } }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/jsonpath/node_modules/escodegen": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", @@ -14047,6 +14553,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -14235,9 +14751,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -14452,9 +14968,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "devOptional": true, "license": "MIT", "engines": { @@ -14553,10 +15069,10 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "peer": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -14622,6 +15138,12 @@ "ufo": "^1.6.1" } }, + "node_modules/module-alias": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.3.4.tgz", + "integrity": "sha512-bOclZt8hkpuGgSSoG07PKmvzTizROilUTvLNyrMqvlC9snhs7y7GzjNWAVbISIOlhCP1T14rH1PDAV9iNyBq/w==", + "license": "MIT" + }, "node_modules/mrklt": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/mrklt/-/mrklt-0.2.0.tgz", @@ -14980,6 +15502,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -15111,6 +15650,61 @@ "node": ">= 0.8" } }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -15194,9 +15788,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15448,9 +16042,9 @@ } }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.1.tgz", + "integrity": "sha512-NWWCCscLjs+cOKF/s/XVNFRW7Yih0fdH+9brffR5NZCy8k42yRdl5KlWKMVXuI1vfCoy4o1z80XR/W/QUb3V3w==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -15484,12 +16078,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", @@ -16919,9 +17507,9 @@ "license": "MIT" }, "node_modules/strtok3": { - "version": "10.3.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", - "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", "license": "MIT", "dependencies": { "@tokenizer/token": "^0.3.0" @@ -17159,6 +17747,16 @@ "node": ">=14.0.0" } }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -17997,9 +18595,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", - "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "license": "MIT", "engines": { "node": ">=18.17" @@ -18059,8 +18657,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "devOptional": true, "license": "MIT", - "optional": true, "engines": { "node": ">= 10.0.0" } @@ -18205,9 +18803,9 @@ "optional": true }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { @@ -19248,6 +19846,22 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/package.json b/package.json index c324505..f7da486 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,24 @@ "private": true, "type": "module", "scripts": { - "build": "npm run build --workspace=packages/mcp-shared && npm run build --workspace=apps/truvera-api", + "postinstall": "node scripts/apply-wallet-patches.js", + "build": "npm run build --workspace=packages/mcp-shared && npm run build --workspace=apps/truvera-api && npm run build --workspace=apps/wallet-server", "build:shared": "npm run build --workspace=packages/mcp-shared", "build:api": "npm run build --workspace=apps/truvera-api", + "build:wallet": "npm run build --workspace=apps/wallet-server", "dev:api": "npm run dev --workspace=apps/truvera-api", + "dev:wallet": "npm run dev --workspace=apps/wallet-server", "test": "npm run test --workspaces", "test:api": "npm run test --workspace=apps/truvera-api", + "test:wallet": "npm run test --workspace=apps/wallet-server", + "test:wallet:integration": "npm run test:integration --workspace=apps/wallet-server", "typecheck": "npm run typecheck --workspaces", "lint": "npm run lint --workspaces", "lint:fix": "npm run lint:fix --workspaces", "docker:build:api": "docker build --build-arg BUILD_NUMBER=\"$(cat apps/truvera-api/.buildnumber)\" -t docknetwork/truvera-api-mcp:latest -t docknetwork/truvera-api-mcp:$(cat apps/truvera-api/.buildnumber) -f apps/truvera-api/Dockerfile .", - "docker:run:api": "docker rm -f truvera-api-mcp || true && docker run -d --name truvera-api-mcp --env-file apps/truvera-api/.env -e MCP_MODE=http -e MCP_PORT=3000 -p 3000:3000 docknetwork/truvera-api-mcp:latest" + "docker:run:api": "docker rm -f truvera-api-mcp || true && docker run -d --name truvera-api-mcp --env-file apps/truvera-api/.env -e MCP_MODE=http -e MCP_PORT=3000 -p 3000:3000 docknetwork/truvera-api-mcp:latest", + "docker:build:wallet": "docker build --build-arg BUILD_NUMBER=\"$(cat apps/wallet-server/.buildnumber)\" -t docknetwork/truvera-wallet-mcp:latest -t docknetwork/truvera-wallet-mcp:$(cat apps/wallet-server/.buildnumber) -f apps/wallet-server/Dockerfile .", + "docker:run:wallet": "docker rm -f truvera-wallet-mcp || true && docker run -d --name truvera-wallet-mcp --env-file apps/wallet-server/.env -e MCP_MODE=http -e MCP_PORT=3001 -p 3001:3001 docknetwork/truvera-wallet-mcp:latest" }, "workspaces": [ "packages/*", @@ -53,5 +60,8 @@ "repository": { "type": "git", "url": "https://github.com/docknetwork/truvera-mcp-server.git" + }, + "devDependencies": { + "patch-package": "^8.0.1" } } diff --git a/packages/mcp-shared/src/server/bootstrap.ts b/packages/mcp-shared/src/server/bootstrap.ts index a6fcaa8..c2c1235 100644 --- a/packages/mcp-shared/src/server/bootstrap.ts +++ b/packages/mcp-shared/src/server/bootstrap.ts @@ -69,11 +69,12 @@ export async function bootstrapMCPServer( // Start the appropriate transport if (transportConfig.mode === "http") { const port = transportConfig.port ?? 3000; - startHTTPTransport({ + await startHTTPTransport({ serverFactory: createServer, MCP_PORT: port, BUILD_INFO: buildInfo, tools, + serviceName: name, }); } else { const server = createServer(); diff --git a/packages/mcp-shared/src/transport/http/index.test.ts b/packages/mcp-shared/src/transport/http/index.test.ts new file mode 100644 index 0000000..741b632 --- /dev/null +++ b/packages/mcp-shared/src/transport/http/index.test.ts @@ -0,0 +1,86 @@ +import http from "node:http"; +import type { AddressInfo } from "node:net"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { findNextAvailablePort, resolvePortConflict } from "./index.js"; + +describe("findNextAvailablePort", () => { + let occupiedServer: http.Server | undefined; + + afterEach(async () => { + if (!occupiedServer) { + return; + } + + await new Promise((resolve, reject) => { + occupiedServer!.close((error?: Error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + + occupiedServer = undefined; + }); + + it("returns a higher port when the starting port is occupied", async () => { + occupiedServer = http.createServer(); + + await new Promise((resolve) => { + occupiedServer!.listen(0, "127.0.0.1", () => resolve()); + }); + + const occupiedPort = (occupiedServer.address() as AddressInfo).port; + const availablePort = await findNextAvailablePort(occupiedPort); + + expect(availablePort).toBeGreaterThan(occupiedPort); + }); +}); + +describe("resolvePortConflict", () => { + it("returns the next port when the user accepts the prompt", async () => { + const promptUser = vi.fn().mockResolvedValue(""); + const findPort = vi.fn().mockResolvedValue(3001); + + await expect( + resolvePortConflict(3000, "wallet-mcp-service", { + isInteractive: true, + findNextAvailablePort: findPort, + promptUser, + }) + ).resolves.toBe(3001); + + expect(findPort).toHaveBeenCalledWith(3001); + expect(promptUser).toHaveBeenCalledWith( + "Port 3000 is already in use. Start wallet-mcp-service on port 3001 instead? [Y/n] " + ); + }); + + it("throws when no interactive terminal is available", async () => { + const promptUser = vi.fn(); + + await expect( + resolvePortConflict(3000, "wallet-mcp-service", { + isInteractive: false, + findNextAvailablePort: vi.fn().mockResolvedValue(3001), + promptUser, + }) + ).rejects.toThrow( + "Port 3000 is already in use. wallet-mcp-service can run on 3001, but no interactive terminal is available to confirm it." + ); + + expect(promptUser).not.toHaveBeenCalled(); + }); + + it("throws when the user declines the alternate port", async () => { + await expect( + resolvePortConflict(3000, "wallet-mcp-service", { + isInteractive: true, + findNextAvailablePort: vi.fn().mockResolvedValue(3001), + promptUser: vi.fn().mockResolvedValue("n"), + }) + ).rejects.toThrow("Startup cancelled because port 3000 is already in use."); + }); +}); \ No newline at end of file diff --git a/packages/mcp-shared/src/transport/http/index.ts b/packages/mcp-shared/src/transport/http/index.ts index f11da81..60e0245 100644 --- a/packages/mcp-shared/src/transport/http/index.ts +++ b/packages/mcp-shared/src/transport/http/index.ts @@ -1,6 +1,8 @@ -import http from "http"; +import http, { type IncomingMessage, type ServerResponse } from "node:http"; +import net from "node:net"; +import readline from "node:readline/promises"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; -import { randomUUID } from "crypto"; +import { randomUUID } from "node:crypto"; import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { ToolDef } from "../../tools/types.js"; @@ -14,7 +16,132 @@ export interface HTTPTransportArgs { serviceName?: string; } -export function startHTTPTransport({ +interface ResolvePortConflictOptions { + isInteractive?: boolean; + findNextAvailablePort?: (startPort: number) => Promise; + promptUser?: (message: string) => Promise; +} + +function isPortInUseError(error: unknown): error is NodeJS.ErrnoException { + return error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "EADDRINUSE"; +} + +async function isPortAvailable(port: number): Promise { + return new Promise((resolve, reject) => { + const probeServer = net.createServer(); + + probeServer.once("error", (error: Error) => { + if (isPortInUseError(error)) { + resolve(false); + return; + } + + reject(error); + }); + + probeServer.once("listening", () => { + probeServer.close((closeError?: Error) => { + if (closeError) { + reject(closeError); + return; + } + + resolve(true); + }); + }); + + probeServer.listen(port, "0.0.0.0"); + }); +} + +export async function findNextAvailablePort(startPort: number): Promise { + for (let candidatePort = startPort; candidatePort <= 65535; candidatePort += 1) { + if (await isPortAvailable(candidatePort)) { + return candidatePort; + } + } + + throw new Error(`No available port found starting at ${startPort}.`); +} + +async function promptUserForAlternatePort(message: string): Promise { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stderr, + }); + + try { + return await rl.question(message); + } finally { + rl.close(); + } +} + +export async function resolvePortConflict( + requestedPort: number, + serviceName: string, + options: ResolvePortConflictOptions = {} +): Promise { + const isInteractive = options.isInteractive ?? Boolean(process.stdin.isTTY && process.stderr.isTTY); + const nextAvailablePort = await (options.findNextAvailablePort ?? findNextAvailablePort)(requestedPort + 1); + + if (!isInteractive) { + throw new Error( + `Port ${requestedPort} is already in use. ${serviceName} can run on ${nextAvailablePort}, but no interactive terminal is available to confirm it.` + ); + } + + const answer = await (options.promptUser ?? promptUserForAlternatePort)( + `Port ${requestedPort} is already in use. Start ${serviceName} on port ${nextAvailablePort} instead? [Y/n] ` + ); + const normalizedAnswer = answer.trim().toLowerCase(); + + if (normalizedAnswer === "" || normalizedAnswer === "y" || normalizedAnswer === "yes") { + return nextAvailablePort; + } + + throw new Error(`Startup cancelled because port ${requestedPort} is already in use.`); +} + +async function listenOnPort(httpServer: http.Server, requestedPort: number, serviceName: string): Promise { + let port = requestedPort; + + while (true) { + try { + await new Promise((resolve, reject) => { + const onError = (error: Error) => { + cleanup(); + reject(error); + }; + + const onListening = () => { + cleanup(); + resolve(); + }; + + const cleanup = () => { + httpServer.off("error", onError); + httpServer.off("listening", onListening); + }; + + httpServer.once("error", onError); + httpServer.once("listening", onListening); + httpServer.listen(port, "0.0.0.0"); + }); + + return port; + } catch (error) { + if (!isPortInUseError(error)) { + throw error; + } + + port = await resolvePortConflict(port, serviceName); + console.error(`[HTTP] Retrying ${serviceName} on port ${port}`); + } + } +} + +export async function startHTTPTransport({ serverFactory, MCP_PORT, BUILD_INFO, @@ -27,7 +154,7 @@ export function startHTTPTransport({ return !!body && typeof body === "object" && "method" in body && (body as Record).method === "initialize"; } - const httpServer = http.createServer(async (req, res) => { + const httpServer = http.createServer(async (req: IncomingMessage, res: ServerResponse) => { // Debug: Log all incoming requests console.error("[DEBUG] Incoming request:", { method: req.method, @@ -68,7 +195,7 @@ export function startHTTPTransport({ if (req.method === "POST") { body = await new Promise((resolve, reject) => { let data = ""; - req.on("data", (chunk) => { + req.on("data", (chunk: Buffer) => { data += chunk; }); req.on("end", () => { @@ -185,12 +312,12 @@ export function startHTTPTransport({ res.end(JSON.stringify({ error: "Not found. Use POST /mcp for MCP communication." })); }); - httpServer.listen(MCP_PORT, "0.0.0.0", () => { - console.error(`${serviceName} started (HTTP streaming mode on port ${MCP_PORT})`); - console.error(` - Build: ${BUILD_INFO.buildNumber} (${BUILD_INFO.timestamp})`); - console.error(` - MCP endpoint: POST http://localhost:${MCP_PORT}/mcp`); - console.error(` - Health check: GET http://localhost:${MCP_PORT}/health`); - }); + const activePort = await listenOnPort(httpServer, MCP_PORT, serviceName); + + console.error(`${serviceName} started (HTTP streaming mode on port ${activePort})`); + console.error(` - Build: ${BUILD_INFO.buildNumber} (${BUILD_INFO.timestamp})`); + console.error(` - MCP endpoint: POST http://localhost:${activePort}/mcp`); + console.error(` - Health check: GET http://localhost:${activePort}/health`); // Handle graceful shutdown process.on("SIGINT", () => { diff --git a/packages/mcp-shared/tsconfig.json b/packages/mcp-shared/tsconfig.json index 917348e..2c09953 100644 --- a/packages/mcp-shared/tsconfig.json +++ b/packages/mcp-shared/tsconfig.json @@ -11,6 +11,7 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, + "types": ["node"], "declaration": true, "declarationMap": true, "sourceMap": true diff --git a/scripts/apply-wallet-patches.js b/scripts/apply-wallet-patches.js new file mode 100644 index 0000000..c0b74af --- /dev/null +++ b/scripts/apply-wallet-patches.js @@ -0,0 +1,59 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { spawnSync } from 'child_process'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..'); +const patchDir = path.join(repoRoot, 'apps/wallet-server/patches'); +const nodeModulesDir = path.join(repoRoot, 'node_modules'); +const patchPackageBinary = process.platform === 'win32' ? 'patch-package.cmd' : 'patch-package'; + +function getPackageNameFromPatchFile(fileName) { + const baseName = fileName.replace(/\.patch$/, ''); + const parts = baseName.split('+'); + + if (baseName.startsWith('@') && parts.length >= 3) { + return `${parts[0]}/${parts[1]}`; + } + + return parts.slice(0, -1).join('+'); +} + +function isPatchPackageAvailable() { + const result = spawnSync(patchPackageBinary, ['--version'], { + cwd: repoRoot, + stdio: 'ignore', + }); + + return result.status === 0; +} + +if (!fs.existsSync(patchDir)) { + process.exit(0); +} + +if (!isPatchPackageAvailable()) { + console.log('Skipping wallet patches because patch-package is not available in this install context.'); + process.exit(0); +} + +const patchFiles = fs.readdirSync(patchDir).filter((file) => file.endsWith('.patch')); +const installedPatchTargets = patchFiles.filter((file) => { + const packageName = getPackageNameFromPatchFile(file); + return packageName && fs.existsSync(path.join(nodeModulesDir, packageName)); +}); + +if (installedPatchTargets.length === 0) { + console.log('Skipping wallet patches because patched wallet dependencies are not installed.'); + process.exit(0); +} + +const result = spawnSync(patchPackageBinary, ['--patch-dir', path.relative(repoRoot, patchDir)], { + cwd: repoRoot, + stdio: 'inherit', +}); + +process.exit(result.status ?? 1); \ No newline at end of file